类的六个默认成员函数

如果一个类中什么成员都没有,则就是空类。但是空类中什么都没有吗?其实并不是这样的,任何类在我们不写的情况下,都会自动生成下面六个默认成员函数。

class Date{};

在这里插入图片描述

初始化和清理

  • 构造函数

    • 构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,但是需要注意的是构造函数的主要任务并不是开空间创建对象,而是初始化对象。
    • 特性:
      • 1、构造函数的名字跟类名相同
      • 2、没有返回值
      • 3、对象实例化时候,编译器自动调用对应的构造参数
      • 4、构造函数可以重载
    #include<iostream>
    using namespace std;
    class date {
    public:
    //从下面可以看到构造函数的名字跟类名相同,并且没有返回值
    	data()
    	{}//无参的构造函数
    	date(int year, int month, int day) {
    		_year = year;
    		_month = month;
    		_day = day;
    	}//有参的构造函数
    	//这两个构造函数构成了函数的重载,因为它们的参数不同
    	void PrintDate() {
    		cout<< _year << "-" << _month << "-" << _day << endl;
    	}
    private:
    	int _year;
    	int _month;
    	int _day;
    };
    int main() {
    	date d1;//调用无参构造函数
    	date d2(2019,07, 11);//调用带参的构造函数
    	d2.PrintDate();
    	return 0;
    }
    
    • 5、如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成。
    	class Date {
    public:
    	void PrintDate() {
    		cout<< _year << "-" << _month << "-" << _day << endl;
    	}
    private:
    	int _year;
    	int _month;
    	int _day;
    };
    void Test(){
    	Date  d;//没有定义构造函数,对象也可以创建成功,因此此处调用的是编译器生成的默认构造函数
    }
    
    • 6、无参构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认成员函数。

      • 无参构造函数:Date(){}
      • 全缺省构造函数:Date(int year=2019,int month=7,int day=11){}
    • 7、如果用户自己没有定义构造函数,则C++系统会自动生成一个构造函数,称作默认构造函数或者缺省构造函数。只是这个构造函数是空的,不执行任何操作。它好像看起来没有什么用处,但是为什么还要存在呢?

      • 因为C++将类型分成内置类型(基本类型)和自定义类型。内置类型就是语法已经定义好的类型:如 int/char…,自定义类型就是我们使用class/union/struct自己定义的类型。看看下面的程序,就会发现编译器生成默认的构造函数会对自定类型成员_t调用它的默认成员函数
      class Time {
      public:
      	Time() {
      		cout << "Time():" << endl;
      		_hour = 0;
      		_minute = 0;
      		_second = 0;
      	}
      private:
      //基本类型(内置类型)
      	int _hour;
      	int _minute;
      	int _second;
      };
      class Date {
      private:
      	int _year;
      	int _month;
      	int _day;
      	//自定义类型
      	Time _t;
      };
      int main() {
      	Date d;
      	system("pause");
      	return 0;
      }
      		
      

      接下来我们看一下它创建对象时的汇编语句
      在这里插入图片描述
      从图上我们看到我们并没有显式的在类中定义构造函数,编译器自动的生成了一个默认的构造函数,此时这个默认的构造函数就有用了,它将会对自定义类型的成员_t调用它的默认成员函数
      在这里插入图片描述

    • 析构函数

      • 析构函数:与构造函数功能相反,析构函数不是完成对象的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成类的一些资源清理工作。
      • 特征:
        • 析构函数名是在类名前加上字符~

        • 无参数无返回值

          ~SeqList(){}
          
        • 一个类有且只有一个析构函数。若未显式定义,系统会自动生成默认的析构函数

        • 对象生命周期结束时,C++编译系统会自动调用析构函数

        • 关于编译器自动生成的析构函数,会对自定义类型成员调用它的析构函数

      拷贝复制

      • 拷贝构造函数

        • 概念:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用
          • 为什么一般常用const修饰?
            • 因为你在拷贝复制的时候可能不小心会把被拷贝的对象给修改了,这样程序的结果可能就不符合预期,如果你加上const的时候,就会出现下面的情况。
              在这里插入图片描述
      • 特征
        • 拷贝构造函数是构造函数的一个重载形式(因为它们在同一个作用域,函数名相同,参数列表不同)

        • 拷贝构造函数的参数只有一个且必须使用引用实参,使用传值方式会引发无穷递归调用

          Date(const Date date){}
          

          当我们用一个对象去拷贝构造另一个对象的时候,如果我们显式定义了拷贝构造函数,则在拷贝构造的时候,编译器则会调用我们自己显式定义的拷贝构造函数。而如果我们使用传值的方式进行拷贝构造的时候,则在调用拷贝构造函数时,编译器会生成一个临时对象。而这个临时对象也会调用拷贝构造函数来完成临时对象的创建,所以就会不断的调用拷贝构造函数,,从而引发无穷递归调用。

        • 若未显式定义,系统会默认生成一个拷贝构造函数。默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝是浅拷贝,或者叫值拷贝

          • 深浅拷贝问题

          在这里插入图片描述
          在这里插入图片描述
          上面我们给出的String类,我们使用s2拷贝构造s1,并且我们使用的是系统给出的默认拷贝构造函数,使用的是浅拷贝。当我们构造完成要释放资源时,则会对同一份内存空间释放两次,所以程序就会崩溃。因此当一个类管理资源的时候,将来这个类我们一定要自己显式的实现它,否则就是浅拷贝,则会引起程序崩溃。

        • 如果我们自己没有实现拷贝构造函数,则编译器也会为我们实现一个默认的拷贝构造函数,那么我们什么时候使用编译器给出的,什么时候我们自己去实现呢?

          • 如果一个类管理资源的时候,就需要我们自己去实现这个拷贝构造函数,如果没有管理资源,如我们前面写的日期类,就可以使用编译器给出的默认拷贝构造函数。
    • 赋值运算符重载

      • 运算符重载
      • 运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似
      • 函数名字为:关键字operator后面接需要重载的运算符符号
      • 函数原型:返回值类型operator操作符(参数列表)
      • 注意:
        • 不能通过连接其他符号来创建新的操作符:如operator@,并且 .*   ::  sizeof  ?:  .这五个运算符不能重载。
        • 重载操作符必须有一个类类型或者枚举类型的操作数
        • 用于内置类型的操作符,其含义不能改变
          • 例如:内置类型的+,不能改变其含义,什么意思?
          int main(){
          int a = 1;
          int b = 2;
          a+b;//这个+号加完之后的结果并没有改变a和b的值,而如果改为a+=b,则结果就会改变a的值,作为内置类型的操作符就会出错
          }
          
        • 作为类成员的重载函数时,其形参看起来比操作数数目少一
          • 因为操作符有一个默认的形参this,限定为第一个形参
      • 赋值运算符重载
        • 赋值运算符主要有四点
          • 参数类型:一个类类型对象
          • 返回值:有返回值
            • d1 = d2 = d3;对于这种连续赋值的时候,要有返回值
          • 检测是否自己给自己赋值
          • 返回*this
          • 一个类如果没有显式定义赋值运算符重载,编译器也会生成一个,完成对象按字节序的拷贝

    取地址重载

    • const成员

      • const修饰类的成员函数:将const修饰的类成员函数称之为const成员函数,const修饰类成员函数,实际上修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改
      • const对象不允许调用非const成员函数,而非const对象可以调用const成员函数
      • const成员函数内不可以调用其它的非const成员函数,而非const成员函数可以调用其他的const成员函数
    • 取地址及const取地址操作符重载
      • 这两个默认成员函数一般不用重新定义,编译器会默认生成
      class Date {
      public:
      	Date* operator&() {
      		return this;
      	}
      	const Date* operator&()const {
      		return this;
      	}
      private:
      	int _year;
      	int _month;
      	int _day;
      };
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值