【C++】C++类和对象详解(上)

目录

思维导图大纲:

 思维方面:

 1.  类的定义:

2.  类的特点:

 3.  this指针:

4.  类的默认成员函数 

 默认构造函数

 1.构造函数 

  2.析构函数

 3.拷贝构造函数

4. 赋值运算符重载 

1. 运算符重载

5. 日期类实现:

Date.h 

Date.cpp

Text.cpp 


思维导图大纲:

 思维方面:

思维方面:由面向过程转化为面向对象
我们造一辆车,我们需要金属框架,轮胎,玻璃窗,发动机等等
面向过程:我们去自己造金属框架,轮胎,玻璃窗,发动机等等,然后组装
面向对象:我们自己不造以上配件,我们直接组装 

 1.  类的定义:

1. C语言中的struct结构体
我们只能在其中放变量
更改更方便的名字需要借助typedef

typedef struct Stack
{int* array;int capacity;int size;
}Stack;

2. C++中的class类
我们可以在其中存放变量,我们将这些变量叫做成员变量
成员变量前最好加_下划线来区分
我们还可以存放函数,我们将这些函数叫做成员函数
我们不用使用typedef直接使用类名 

class Stack
{// 成员函数// 初始化void Init();// 销毁void Destroy();// 成员变量int* _array;int _capacity;int _size;
};

2.  类的特点:

  (1) 类域
 我们之前了解了命名空间域,全局域,局部域
 在类里面也被类域保护,声明和定义分离时需要表明

class Stack
{// 成员函数// 声明在内// 初始化void Init(int n = 4);// 销毁void Destroy();// 成员变量int* _array;int _capacity;int _size;
};// 定义在外
// 需要使用Stack::声明类域
void Stack::Init(int n)
{_array = (int*)malloc(sizeof(int) * n);if (_array == nullptr){perror("malloc fail!");return;}_capacity = n;_size = 0;
}

 (2)访问限定符
 我们知道类的成员函数和成员变量属于类域内,当我们主函数去调用时访问权限不够
 类的默认权限为私有——private
 类的三大权限:public-公有,private—私有,protect-保护
 想要访问类需要将权限改为公有,但默认我们不去修改类的成员变量,所以我们只将成员函数设为公有 

class Stack
{
public:// 成员函数// 初始化void Init(int n = 4){_array = (int*)malloc(sizeof(int) * n);if (_array == nullptr){perror("malloc fail!");return;}_capacity = n;_size = 0;}// 销毁void Destroy(){free(_array);_array = nullptr;_capacity = 0;_size = 0;}private:// 成员变量int* _array;int _capacity;int _size;
};

类的实列化:
前面的类只是声明,我们需要定义-即开空间
说人话就是:前面的类就好比一张图纸,我们实例化就是根据这张图纸建筑房子
类和对象的关系是:一对多,一张图纸可以盖很多很多相同的房子 

int main()
{// 类的实列化Stack st;st.Init();st.Destroy();return 0;
}

对象的大小计算和c语言的结构体的内存对齐规则一模一样
首先我们的类中的成员函数会被多次调用,不同的对象都会去调用,所以我们为了节省空间
不将成员函数放在类中存储,我们将成员函数放在公共区域
类中存储的只有成员变量
类内部没有成员变量的,只有成员函数或者什么都没有默认给一个字节用于对象占位标识,表示存在 

class A
{
public:void Print(){cout << "void Print()" << endl;}private:char _a;int _b;double _c;
};class B
{
public:void Print(){cout << "void Print()" << endl;}
};class C
{};class D
{
public:void Print(){cout << "void Print()" << endl;}
private:A _d;int _e;
};int main()
{// 实例化A a;B b;C c;D d;// 输出大小cout << sizeof(a) << endl;cout << sizeof(b) << endl;cout << sizeof(c) << endl;cout << sizeof(d) << endl;return 0;
}

 

 3.  this指针:

不存放在类,存放在栈,有些编译器也存放在寄存器中

class Date
{
public:/*void Init(Date* this, int year = 1949, int month = 1, int day = 1){this->_year = year;this->_month = month;this->_day = day;}*/void Init(int year = 1949, int month = 1, int day = 1){_year = year;_month = month;_day = day;}/*void Print(){cout << this->_year << "/" << this->_month << "/" << this->_day << endl;}*/void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;
};int main()
{// 我们定义两个对象进行初始化Date d1;Date d2;d1.Init(2024, 7, 11);d2.Init(2024, 8, 1);d1.Print();d2.Print();// 为什么调用同一个函数,但是却给不同对象初始化不同值,这边也没传地址啊?// 其实默认传了地址,并且使用this指针对不同的对象进行了初始化// 但是this指针不可以显示成为参数,可以在函数内部显示使用和返回return 0;
}

考察理解this指针的题目 

class A
{
public:void Print(){cout << "void Print()" << endl;}
private:int _a;
};class B
{
public:void Print(){cout << "void Print()" << endl;cout << this->_a << endl;}
private:int _a;
};int main()
{A* a = nullptr;a->Print();B* b = nullptr;b->Print();// 以上两个程序语句分别是1.报错,2.运行崩溃,3.成功运行?return 0;
}

 类A只是传过去nullptr但是this没有进行解引用和访问操作所以程序成功运行。

类B传过去nullptr并且进行了访问操作所以程序崩溃。

4.  类的默认成员函数 

什么是默认成员函数,简单说我们不去实现,编译器也会默认生成这些成员函数 

 默认构造函数

 下面以栈类介绍类的默认函数

 1.构造函数 


 函数名与类名一样,无返回值
 全缺省构造函数
 我们不自己实现构造函数,编译器会默认生成一个无参构造函数,这个函数对内置类型不做处理,对自定义类型会去调用他们的构造函数
 无参构造函数,全缺省构造函数,编译器默认生成的无参构造函数都可以称作为默认构造,不传参即可调用的构造为默认构造
 无参构造函数,全缺省构造函数,编译器默认生成的无参构造函数三者只能存在一个
 相当于Stack中的Init

class Stack
{
public:// 无参构造函数/*Stack(){cout << "Stack():无参构造" << endl;_array = (int*)malloc(sizeof(int) * 4);if (nullptr == _array){perror("malloc fail!");exit(-1);}_capacity = 4;_size = 0;}*/// 全缺省构造函数Stack(int n = 4){cout << "Stack():全缺省构造函数" << endl;_array = (int*)malloc(sizeof(int) * n);if (nullptr == _array){perror("malloc fail!");exit(-1);}_capacity = n;_size = 0;}
private:int* _array;int _capacity;int _size;
};int main()
{Stack st;return 0;
}

  2.析构函数


 函数名与类名一样,但是需要在最前面加上~取反符号,无返回值
 析构函数我们不去实现编译器也会自动默认生成,
 对于动态内存申请的空间我们需要自己实现析构函数手动释放
 对于没有动态申请的类,我们不用实现析构函数,编译器默认生成的析构函数即可完成

// 析构函数
~Stack()
{cout << "~Stack()::析构函数" << endl;free(_array);_array = nullptr;_capacity = _size = 0;
}

 3.拷贝构造函数


 拷贝构造函数是构造函数的重载,函数一致,参数不同
 对于表面的值拷贝属于浅拷贝,我们不用实现,编译器自动生成的即可
 对于像栈一类的拷贝属于深拷贝,我们需要自己实现,另外开辟空间,将值拷贝到新的空间上 

	// 拷贝构造函数Stack(const Stack& s) // 使用const修饰放在修改来源{cout << "Stack(const Stack& s)::拷贝构造函数" << endl;_array = (int*)malloc(sizeof(int) * s._capacity);if (nullptr == _array){perror("malloc fail!");exit(-1);}memcpy(_array, s._array, sizeof(int) * s._capacity);_capacity = s._capacity;_size = s._size;}

4. 赋值运算符重载 

1. 运算符重载

• 当运算符被⽤于类类型的对象时,C++语⾔允许我们通过运算符重载的形式指定新的含义。C++规定类类型对象使⽤运算符时,必须转换成调⽤对应运算符重载,若没有对应的运算符重载,则会编译报错。

• 运算符重载是具有特名字的函数,他的名字是由operator和后⾯要定义的运算符共同构成。和其他函数⼀样,它也具有其返回类型和参数列表以及函数体。

• 重载运算符函数的参数个数和该运算符作⽤的运算对象数量⼀样多。⼀元运算符有⼀个参数,⼆元运算符有两个参数,⼆元运算符的左侧运算对象传给第⼀个参数,右侧运算对象传给第⼆个参数。

• 如果⼀个重载运算符函数是成员函数,则它的第⼀个运算对象默认传给隐式的this指针,因此运算符重载作为成员函数时,参数⽐运算对象少⼀个。

• 运算符重载以后,其优先级和结合性与对应的内置类型运算符保持⼀致。

• 不能通过连接语法中没有的符号来创建新的操作符:⽐如operator@

.*    ::    sizeof     ?:     .

• 注意以上5个运算符不能重载。

• 重载操作符⾄少有⼀个类类型参数,不能通过运算符重载改变内置类型对象的含义,如: int

operator+(int x, int y)

• ⼀个类需要重载哪些运算符,是看哪些运算符重载后有意义,⽐如Date类重载operator-就有意义,但是重载operator+就没有意义。

 • 重载++运算符时,有前置++和后置++,运算符重载函数名都是operator++,⽆法很好的区分。C++规定,后置++重载时,增加⼀个int形参,跟前置++构成函数重载,⽅便区分。 

5. 日期类实现:

在日期类实现当中,我们会去应用类的默认构造函数,以及运算符重载

Date.h 

#pragma once
#include <iostream>
#include <stdbool.h>using namespace std;class Date
{
public:// 日期类默认构造函数Date(int year = 1949, int month = 10, int day = 1);// 没有资源申请不用实现析构函数// ~Date();// 打印日期void Print();// 日期类拷贝构造函数Date(const Date& d);// 获取某日期的天数int GetMonthDay(const Date& d){static int arr_day[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 };if (d._month == 2 && ((d._year % 4 == 0) && (d._year % 100 != 0) || (d._year % 400 == 0))){return 29;}return arr_day[d._month];}// 运算符重载// d1 = d2 , return Date&类型Date& operator=(const Date& d);// d1+=day , return Date&类型Date& operator+=(int day);// d1+day, return Date类型Date operator+(int day);// d1-=day , return Date&类型Date& operator-=(int day);// d1-day, return Date类型Date operator-(int day);// d1 == d2 , return bool类型bool operator==(const Date& d);// d1 != d2 , return bool类型bool operator!=(const Date& d);// 前置++ 后置++// ++d1 -> d1.operator++(&d);Date& operator++();// d1++ -> d1.operator++(&d, 0);Date operator++(int);// 比较大小// >bool operator>(const Date& d);// <bool operator<(const Date& d);// >=bool operator>=(const Date& d);// <=bool operator<=(const Date& d);// 日期-日期 , return int -> 天数int operator-(const Date& d);private:// 年/月/日int _year;int _month;int _day;
};

Date.cpp

#include "Date.h"// 日期类默认构造函数
Date::Date(int year, int month, int day) // 这边缺省参数声明和定义只需要在声明时显示写出即可
{cout << "日期类默认构造函数" << endl;_year = year;_month = month;_day = day;
}// 打印日期
void Date::Print()
{cout << _year << "/" << _month << "/" << _day << endl;
}// 日期类拷贝构造函数
Date::Date(const Date& d)
{cout << "日期类拷贝构造函数" << endl;_year = d._year;_month = d._month;_day = d._day;
}// 运算符重载// d1 = d2 , return Date类型
Date& Date::operator=(const Date& d)
{cout << "Date& Date::operator=(const Date& d)" << endl;_year = d._year;_month = d._month;_day = d._day;return *this;
}// d1+=day , return Date&类型
Date& Date::operator+=(int day)
{if (day < 0){return *this -= (-day);}_day += day;while (_day > GetMonthDay(*this)){_day -= GetMonthDay(*this);++_month;if (_month == 13){++_year;_month = 1;}}return *this;
}// d1+day, return Date类型
Date Date::operator+(int day)
{Date tmp = *this;tmp += day;return tmp;
}// d1-=day , return Date&类型
Date& Date::operator-=(int day)
{if (day < 0){return *this += (-day);}_day -= day;while (_day <= 0){--_month;if (_month == 0){--_year;_month = 12;}_day += GetMonthDay(*this);}return *this;
}// d1-day, return Date类型
Date Date::operator-(int day)
{Date tmp = *this;tmp -= day;return tmp;
}// 前置++ 后置++// ++d1 -> d1.operator++(&d);
Date& Date::operator++()
{*this += 1;return *this;
}// d1++ -> d1.operator++(&d, 0);
Date Date::operator++(int)
{Date ret(*this);*this += 1;return ret;
}// d1 == d2 , return bool类型
bool Date::operator==(const Date& d)
{return _year == d._year && _month == d._month && _day == d._day;
}// d1 != d2 , return bool类型
bool Date::operator!=(const Date& d)
{return !(*this == d);
}// 比较大小// >
bool Date::operator>(const Date& d)
{if (_year > d._year){return true;}else if (_year == d._year){if (_month > d._month){return true;}else if (_month == d._month){if (_day > d._day){return true;}else {return false;}}else {return false;}}else {return false;}
}// <
bool Date::operator<(const Date& d)
{return !(*this >= d);
}// >=
bool Date::operator>=(const Date& d)
{return *this > d || *this == d;
}// <=
bool Date::operator<=(const Date& d)
{return !(*this > d);
}// 日期-日期 , return int -> 天数
int Date::operator-(const Date& d)
{int flag = 1;Date max = *this;Date min = d;// 假设法if (*this < d){min = *this;max = d;flag = -1;}int day = 0;while (min < max){++min;++day;}return day * flag;}

Text.cpp 

#include "Date.h"void Text01()
{// 测试默认构造//Date d1;//d1.Print();//Date d2(2024, 7, 21);//d2.Print();// 测试拷贝构造函数//Date d1(2024, 7, 21);//d1.Print();//Date d2(d1);//d2.Print();//Date d2 = d1;//d2.Print();// 测试运算符重载(=)//Date d1(2024, 7, 21);//Date d2, d3;//d2 = d3 = d1;//d1.Print();//d2.Print();//d3.Print();// 测试运算符重载(+=)//Date d1(2024, 7, 21);//d1 += 50000;//d1.Print();// 测试运算符重载(+)//Date d1(2024, 7, 21);//Date d2(d1 + 50000);//d1.Print();//d2.Print();// 测试运算符重载(-=)//Date d1(2024, 7, 21);//d1 -= 50000;//d1.Print();// 测试运算符重载(-)//Date d1(2024, 7, 21);//Date d2(d1 - 50000);//d1.Print();//d2.Print();// 测试运算符重载(前置++)/*Date d1(2024, 7, 31);Date d2(++d1);d1.Print();d2.Print();*/// 测试运算符重载(后置++)//Date d1(2024, 7, 31);//Date d2(d1++);//d1.Print();//d2.Print();// 测试运算符重载(==)//Date d1(2024, 7, 31);//Date d2(2024, 7, 31);//bool ret = (d1 == d2);//cout << ret << endl;// 测试运算符重载(!=)//Date d1(2024, 7, 31);//Date d2(2024, 7, 21);//bool ret = (d1 != d2);//cout << ret << endl;// 测试运算符重载(>)//Date d1(2024, 7, 31);//Date d2(2024, 7, 21);//bool ret = (d1 > d2);//cout << ret << endl;// 测试运算符重载(>=)//Date d1(2024, 7, 31);//Date d2(2024, 7, 31);//bool ret = (d1 >= d2);//cout << ret << endl;// 测试运算符重载(<)//Date d1(2024, 7, 31);//Date d2(2024, 7, 31);//bool ret = (d1 < d2);//cout << ret << endl;// 测试运算符重载(<=)//Date d1(2024, 7, 31);//Date d2(2024, 7, 31);//bool ret = (d1 <= d2);//cout << ret << endl;// 测试运算符重载(日期-日期)//Date d1(1958, 7, 11);//Date d2(2024, 7, 21);//cout << d1 - d2 << endl;}int main()
{Text01();return 0;
}

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/381525.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【IntelliJ IDEA】一篇文章集合所有IDEA的所有设置

IntelliJ IDEA 是一款功能强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;其设置涵盖了多个方面&#xff0c;以满足不同开发者的需求和偏好。由于 IDEA 的设置相当复杂和详尽&#xff0c;这里无法在一篇简短的文章中详细介绍所有设置。然而&#xff0c;我可以提供一…

AV1技术学习:Intra Prediction

对于帧内预测模式编码块&#xff0c;亮度分量的预测模式和色度分量的预测模式在比特流中分别发出信号。亮度预测模式是基于相邻左侧和上侧两个编码块预测上下文的概率模型进行熵编码的。色度预测模式的熵编码取决于色度预测模式的状态。帧内预测以变换块为单位&#xff0c;并使…

VB之制作一个简易计算器

文章目录 创建制作界面设置文本样式技巧双击控件实现功能完整代码vb.net十分适合用于快速开发windows下的桌面程序 创建 制作界面 20个button 一个richtextbox 设置文本样式技巧 ‘左键框选全部控件,进行统一属性设置!’ 双击控件实现功能 注意控件ID与函数对应 完整代码…

首个WebAgent在线评测框架和流程数据管理平台来了,GPT-4、Qwen登顶闭源和开源榜首!

在当今科技迅速发展的时代&#xff0c;大型语言模型&#xff08;Large Language Model&#xff0c;LLM&#xff09;正以前所未有的速度改变着我们与数字世界的互动方式。基于LLM的智能代理&#xff08;LLM Agent&#xff09;&#xff0c;从简单的信息搜索到复杂的网页操作&…

压缩pdf大小的方法 指定大小软件且清晰

在数字化时代&#xff0c;pdf文件因其良好的兼容性和稳定性&#xff0c;已成为文档分享的主流格式。然而&#xff0c;高版本的pdf文件往往体积较大&#xff0c;传输和存储都相对困难。本文将为您详细介绍几种简单有效的方法&#xff0c;帮助您减小pdf文件的大小&#xff0c;让您…

MacOS M1 安装item2 并配置Zsh

文章目录 1 下载item22 美化item22.1 配置主题2.2 设置黑色的主题&#xff1a;2.3 配置显示状态栏 status bar 3 安装 Oh my zsh3.1 设置主题3.2 设置插件3.3 安装第三方插件1 下载仓库解压2 使用 git clone 一些常用插件以及其作用 参考 1 下载item2 MacOS自带终端&#xff0…

使用小波分析实现文字种类自动识别

文章目录 数据简介开始实验小波分解得出结果结果分析误差分析参考文献 数据简介 各找一篇中文&#xff0c;日文&#xff0c;韩文&#xff0c;英文&#xff0c;俄文较长的学术论文。将论文转化为JPG格式。拆分每张JPG生成更多小的JPG。最终获得很多5个不同语言的JPG并且自带标签…

go中map

文章目录 Map简介哈希表与Map的概念Go语言内建的Map类型Map的声明Map的初始化Map的访问Map的添加和修改Map的删除Map的遍历 Map的基本使用Map的声明与初始化Map的访问与操作Map的删除Map的遍历Map的并发问题实现线程安全的Map 3. Map的访问与操作3.1 访问Map元素代码示例&#…

python—爬虫爬取视频样例

下面是一个使用Python爬虫爬取视频的基本例子。创建一个Python爬虫来爬取视频通常涉及到几个步骤&#xff1a;发送HTTP请求、解析网页内容、提取视频链接、下载视频文件。 import jsonimport requests from lxml import etreeif __name__ __main__:# UA伪装head {"User…

持续集成07--Jenkins配置Allure测试报告

前言 在持续集成&#xff08;CI&#xff09;流程中&#xff0c;自动化测试报告是评估软件质量和追踪问题的重要工具。Allure Framework作为一个轻量级且功能丰富的测试报告工具&#xff0c;能够生成详细的测试报告&#xff0c;帮助团队更好地理解测试结果。本章节“持续集成07-…

深度学习每周学习总结N4:中文文本分类-Pytorch实现(基本分类(熟悉流程)、textCNN分类(通用模型)、Bert分类(模型进阶))

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 目录 0. 总结&#xff1a;1. 基础模型a. 数据加载b. 数据预处理c. 模型搭建与初始化d. 训练函数e. 评估函数f.拆分数据集运行模型g. 结果可…

Qt QProcess 进程间通信读写数据通信

本文介绍了如何使用Qt的QProcess 进行程序开发&#xff0c;包括启动进程间通信、设置环境变量、通用方法&#xff1b;方便在日常开发中使用&#xff1b; 1.使用Qt进行程序开发&#xff0c;可以通过QProcess类用于启动外部程序并与其进行通信.&#xff1b; 进程A&#xff08;…

Grafana :利用Explore方式实现多条件查询

背景 日志统一推送到Grafana上管理。所以&#xff0c;有了在Grafana上进行日志搜索的需求&#xff0c;而进行日志搜索通常需要多条件组合。 解决方案 通过Grafana的Explore的方式实现多条件查询。 直接看操作步骤&#xff1a; 在主页搜索框中输入“Explore” 进入这个界面…

Linux下开放指定端口

比如需要开放82端口&#xff1a; #查询是否开通 firewall-cmd --query-port82/tcp#开放端口82 firewall-cmd --zonepublic --add-port82/tcp --permanent#重新加载防火墙 firewall-cmd --reload

[计算机网络] VPN技术

1. 概述 虚拟专用网络&#xff08;VPN&#xff09;技术利用互联网服务提供商&#xff08;ISP&#xff09;和网络服务提供商&#xff08;NSP&#xff09;的网络基础设备&#xff0c;在公用网络中建立专用的数据通信通道。VPN的主要优点包括节约成本和提供安全保障。 优点&#…

Android RSA 加解密

文章目录 一、RSA简介二、RSA 原理介绍三、RSA 秘钥对生成1. 密钥对生成2. 获取公钥3. 获取私钥 四、PublicKey 和PrivateKey 的保存1. 获取公钥十六进制字符串1. 获取私钥十六进制字符串 五、PublicKey 和 PrivateKey 加载1. 加载公钥2. 加载私钥 六、 RSA加解密1. RSA 支持三…

[HTML]一文掌握

背景知识 主流浏览器 浏览器是展示和运行网页的平台&#xff0c; 常见的五大浏览器有 IE浏览器、火狐浏览器&#xff08;Firefox&#xff09;、谷歌浏览器&#xff08;Chrome&#xff09;、Safari浏览器、欧朋浏览器&#xff08;Opera&#xff09; 渲染引擎 浏览器解析代码渲…

Go语言 Import导入

本文主要介绍Go语言import导入使用时注意事项和功能实现示例。 目录 Import 创建功能文件夹 加法 减法 主函数 优化导入的包名 .引入方法 总结 Import 创建功能文件夹 做一个计算器来演示&#xff0c;首先创建test文件夹。 加法 在test文件夹中创建add文件夹&#xff…

高性能分布式IO系统BL205 OPC UA耦合器

边缘计算是指在网络的边缘位置进行数据处理和分析&#xff0c;而不是将所有数据都传送到云端或中心服务器&#xff0c;这样可以减少延迟、降低带宽需求、提高响应速度并增强数据安全性。 钡铼BL205耦合器就内置边缘计算功能&#xff0c;它不依赖上位机和云平台&#xff0c;就能…

大语言模型-Transformer-Attention Is All You Need

一、背景信息&#xff1a; Transformer是一种由谷歌在2017年提出的深度学习模型。 主要用于自然语言处理&#xff08;NLP&#xff09;任务&#xff0c;特别是序列到序列&#xff08;Sequence-to-Sequence&#xff09;的学习问题&#xff0c;如机器翻译、文本生成等。Transfor…