目录
1.析构函数
- 1.概念
-
- 析构函数:与构造函数功能相反,析构函数不是完成对象本身的销毁,局部对象销毁工作是由编译器完成的。而 对象在销毁时会自动调用析构函数,完成类的一些资源清理工作。
- 资源:堆上申请的内存空间、文件指针、套接字等等。
- 2 特性
- 析构函数是特殊的成员函数。
- 1. 析构函数名是在类名前加上字符 ~。
- 2. 无参数无返回值。
-
-
- 3. 一个类有且只有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载(析构函数不需要参数)。
-
- 4. 对象生命周期结束时,C++编译系统自动调用析构函数。
-
2.拷贝构造函数
- 那在创建对象时,可否创建一个与一个对象一某一样的新对象呢?
- 可以
-
- 用对象d1去初始化对象d2
- 1 概念
- 拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。
- 2 特征
- 1. 拷贝构造函数是构造函数的一个重载形式。
-
- 2. 拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。
-
- 3. 若未显示定义,系统生成默认的拷贝构造函数。
- 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝我们叫做浅拷贝,或者值拷贝(即内存中有啥就拷贝啥)。
-
- 栈
-
typedef int Datatype; class Stack{ public: Stack(){ Datatype* temp = (Datatype*)malloc(sizeof(Datatype)* 3); if (NULL == temp){ perror("malloc:"); return; } _array = temp; _capacity = 3; _size = 0; } ~Stack(){ if (_array){ free(_array); _array = NULL; _capacity = 0; _size = 0; } } private: void checkStack(){ if (_capacity == _size){ int newcapacity = _capacity * 2; Datatype*temp = (Datatype*)malloc(sizeof(Datatype)*newcapacity); if (temp == NULL){ perror("malloc:"); return; } memcpy(temp, _array, sizeof(Datatype)*_capacity); _capacity = newcapacity; } } Datatype* _array; int _capacity; int _size; }; int main(){ Stack s1; Stack s2(s1); return 0; }
-
- 由于s2 是s1的浅拷贝,s1和s2中的_array指向了堆上的同一块内存,在销毁栈的时候,先销毁s2,s2中_array指向的内存空间就会被释放,s1在销毁栈的时候,s1中的_array已成为野指针,就会导致程序崩溃。
- 1. 拷贝构造函数是构造函数的一个重载形式。
- 5.拷贝构造的数典型调用场景:
- 使用已存在对象创建新对象
- 函数参数类型为类类型对象
- 函数返回值类型为类类型对象
-
- 为了提高程序效率,一般对象传参时,尽量使用引用类型,返回时根据实际场景,能用引用尽量使用引用。
-
3.运算符重载
- 5.1 运算符重载
- C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
- 函数名字为:关键字operator后面接需要重载的运算符符号。
- 函数原型:返回值类型 operator操作符(参数列表)
- 注意:
- 不能通过连接其他符号来创建新的操作符:比如operator@
-
- 重载操作符必须有一个类类型或者枚举类型的操作数
-
- 用于内置类型的操作符,其含义不能改变,例如:内置的整型+,不能改变其含义
- 作为类成员的重载函数时,其形参看起来比操作数数目少1,成员函数的操作符有一个默认的形参this,限定为第一个形参
-
- .* 、:: 、sizeof 、?: 、. 注意以上5个运算符不能重载。
- 不能通过连接其他符号来创建新的操作符:比如operator@
- 5.2 赋值运算符重载
- 赋值运算符重载必须是成员函数
-
-
- 原因:赋值运算符如果不显式实现,编译器会生成一个默认的。 此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数。
-
- 赋值运算符重载格式
- 参数类型: constT&. 传递弓引|用可以提高传参效率
- 返回值类型: T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
- 返回*this:要复合连续赋值的含义
- 连续赋值场景(无返回值)
- 改进,返回*this
-
-
- 连续赋值场景(无返回值)
- 检测是否自己给自己赋值
-
- 用户没有显示实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝(浅拷贝)。
- 当类中涉及到资源管理时,赋值运算符是一定要重载的
-
- 赋值运算符重载必须是成员函数
- 前置++和后置++重载
-
- 编译器在编译的时候,编译器会判断++在对象前,还是在对象后,进而调用对应的运算符重载函数
-
4.const修饰类的成员函数
- 将const修饰的类成员函数称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。
- const放在返回值前面,则修饰的是返回值
- const放在参数列表的位置,则修饰的是参数
-
- const放在函数之后,则修饰的是函数,即const修饰的成员函数,在const成员函数中,不能修改当前对象中的“成员变量”
-
- 普通类型对象,对于const成员函数和普通成员函数都可调用,普通对象本来就是一个可读可写的对象
- 1. const对象不能调用非const成员函数。const对象只能读,不能写,在普通的成员函数中可能会对对象进行修改。
- 2. 非const对象可以调用const成员函数。
- 为了提高程序的安全性,如果成员函数内部确定一 定会修改当前对象中的成员变量,最好将该成员函数设置为const类型
- 4. 非const成员函数内可以调用其它的const成员函数。
- 3. const成员函数内不可以调用其它的非const成员函数。
-
- mutable关键字
- mutable修饰的成员变量在const成员函数中可以被修改
-