析构/拷贝构造/运算符重载/const修饰的成员函数

目录

1.析构函数

2.拷贝构造函数

3.运算符重载

4.const修饰类的成员函数


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已成为野指针,就会导致程序崩溃。
  • 5.拷贝构造的数典型调用场景:
    • 使用已存在对象创建新对象
    • 函数参数类型为类类型对象
    • 函数返回值类型为类类型对象
    • 为了提高程序效率,一般对象传参时,尽量使用引用类型,返回时根据实际场景,能用引用尽量使用引用。

3.运算符重载

  • 5.1 运算符重载
    • C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
    • 函数名字为:关键字operator后面接需要重载的运算符符号。
    • 函数原型:返回值类型 operator操作符(参数列表)
    • 注意:
      • 不能通过连接其他符号来创建新的操作符:比如operator@
      • 重载操作符必须有一个类类型或者枚举类型的操作数
      • 用于内置类型的操作符,其含义不能改变,例如:内置的整型+,不能改变其含义
      • 作为类成员的重载函数时,其形参看起来比操作数数目少1,成员函数的操作符有一个默认的形参this,限定为第一个形参
      • .* 、:: 、sizeof 、?: 、. 注意以上5个运算符不能重载。
  • 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成员函数中可以被修改

猜你喜欢

转载自blog.csdn.net/sy2453/article/details/123708229