拷贝构造函数和赋值运算符重载

本文介绍了C++中的拷贝构造函数和赋值运算符重载。拷贝构造函数在创建新对象时由编译器自动调用,通常用于深拷贝或浅拷贝。如果需要进行深拷贝,需要自定义拷贝构造函数。赋值运算符重载增强了代码可读性,其成员函数形式保证了成员变量的安全性,并且在涉及深拷贝时需要自定义以避免程序崩溃。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 拷贝构造函数

    只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象 创建新对象时由编译器自动调用

    1.1构造函数的特性

    1. 拷贝构造函数是构造函数的一个重载形式

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

      代码演示:

      #include<iostream>
      
      #include<iostream>
      #include<stdlib.h>
      
      using std::cout;
      using std::endl;
      
      class Date
      {
      public:
      	Date(int year, int month, int day)
      	{
      		_year = year;
      		_month = month;
      		_day = day;
      	}
      	
      	Date(const Date& d)
      	{
      		_year = d._year;
      		_month = d._month;
      		_day = d._day;
      	}
      	
      	/*
      	拷贝构造函数的参数如果是传值,那么将会报错,因为会产生无穷递归
      	Date(const Date d)
      	{
      		_year = d._year;
      		_month = d._month;
      		_day = d._day;
      	}
      	*/
      	
      	void Print()
      	{
      		cout << _year << "-" << _month << "-" << _day << endl;
      	}
      private:
      	int _year;
      	int _month;
      	int _day;
      };
      
      int main()
      {
      	Date d1(1900,1,1);
      	Date d2 = d1;
      	d2.Print();
      }
      

      输出结果为:1900-1-1
      注意:拷贝构造函数传值操作之所以会产生无穷递归是因为在栈帧上,到要向拷贝构造函数传参的时候,要将参数d1复制一份,此时就又会创建一个拷贝构造函数,这时还需要传参,所以需要将d1复制一份,那么就又得创建拷贝构造函数,以此往后不停地需要传参,也不停地需要创建新的拷贝构造函数,而传引用在传参的时候,就等于是将d1传了过去,不需要复制任何东西

    3. 若未显示定义,系统会生成默认的拷贝构造函数,但是这种默认的拷贝构造函数只能是浅拷贝,当我们需要深拷贝一段数据的时候,还需要自己来创建一个拷贝构造函数

      代码演示:

      #include<iostream>
      
      using std::cout;
      using std::endl;
      
      class Date
      {
      public:
      	Date(int year, int month, int day)
      	{
      		_year = year;
      		_month = month;
      		_day = day;
      	}
      	void Print()
      	{
      		cout << _year << "-" << _month << "-" << _day << endl;
      	}
      private:
      	int _year;
      	int _month;
      	int _day;
      };
      
      int main()
      {
      	Date d1(1900, 1, 1);
      	Date d2 = d1;
      	d2.Print();
      }
      

      输出结果为:1990-1-1

      注意:当需要拷贝的内容不牵扯内存的时候,则用编译器默认生成的拷贝构造函数来进行浅拷贝是没有任何问题的,但是下面的代码在运行的时候则会崩溃

      #include<iostream>
      
      using std::cout;
      using std::endl;
      
      class string
      {
      public:
      	string(const char* str = "hello world")
      	{
      		_str = (char*)malloc(strlen(str) + 1);
      		strcpy(_str, str);
      	}
      
      	~string()
      	{
      		free(_str);
      		_str = NULL;
      	}
      	/*
      	如果没有自己创建这个拷贝构造函数,那么程序就会崩溃
      	string(const string& str)
      	{
      		_str = (char*)malloc(strlen(str._str) + 1);
      		strcpy(_str, str._str1);
      	}
      	*/
      	void Print()
      	{
      		cout << _str << endl;
      	}
      private:
      	char* _str;
      };
      
      int main()
      {
      	string str1("hello");
      	string str2 = str1;
      	str2.Print();
      }
      

      输出结果为:0

      注意:想要代码成功运行只要放开我注释的哪一个部分即可,很明显涉及深拷贝的情况,编译器默认生成的拷贝构造函数将无法使用,需要自己手动创建一个

  2. 赋值运算符重载

    2.1.运算符重载

    C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类 型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似

    函数原型:返回值类型 operator操作符(参数列表)

    注意:
    1.不能通过连接其他符号来创建新的操作符:比如operator@
    2.重载操作符必须有一个类类型或者枚举类型的操作数
    3.用于内置类型的操作符,其含义不能改变,例如:内置的整型+,不 能改变其含义
    4.作为类成员的重载函数时,其形参看起来比操作数数目少1成员函数的 操作符有一个默认的形参this,限定为第一个形参
    5.(.*) 、(:: ) 、(sizeof) 、(?:三目运算符) 、(.) 以上5个运算符不能重载

    代码演示:

    #include<iostream>
    
    using std::cout;
    using std::endl;
    
    class Date
    {
    public:
    	Date(int year=1990,int month=1,int day=1)
    	{
    		_year = year;
    		_month = month;
    		_day = day;
    	}
    
    	void print()
    	{
    		cout << _year << "-" << _month << "-" << _day << endl;
    	}
    	int _year;
    	int _month;
    	int _day;
    };
    
    //全局operator,类的成员变量必须是共有的
    bool operator==(const Date& d1,const Date& d2)
    {
    	return d1._year == d2._year
    		&& d1._month == d2._month
    		&& d1._day == d2._day;
    }
    
    int main()
    {
    	Date d1(2019, 5, 14);
    	Date d2;
    	cout << (d1 == d2) << endl;
    }
    

    注意:当operator处于全局的时候就不能再保持成员变量的安全性,所以operator一般是当做成员函数使用的

    代码演示:

    #include<iostream>
    
    using std::cout;
    using std::endl;
    
    class Date
    {
    public:
    	Date(int year = 1990, int month = 1, int day = 1)
    	{
    		_year = year;
    		_month = month;
    		_day = day;
    	}
    
    	void print()
    	{
    		cout << _year << "-" << _month << "-" << _day << endl;
    	}
    	// bool operator==(Date* this, const Date& d2)    
    	// 这里需要注意的是,左操作数是this指向的调用函数的对象 
    	bool operator==(const Date& d2)
    	{
    		return this->_year == d2._year
    			&& this->_month == d2._month
    			&& this->_day == d2._day;
    	}
    private:
    	int _year;
    	int _month;
    	int _day;
    };
    
    int main()
    {
    	Date d1(2019, 5, 14);
    	Date d2;
    	cout << (d1 == d2) << endl;
    }
    

    2.2.赋值运算符重载

    注意:
    1.返回值是*this
    2.赋值运算符重载用的是必须是两个已经存在的对象
    3.一个类如果没有显式定义赋值运算符重载,编译器也会生成一个,完成对象按字节序的值拷贝(浅拷贝)

    代码演示:

    #include<iostream>
    
    using std::cout;
    using std::endl;
    
    class Date
    {
    public:
    	Date(int year = 1990, int month = 1, int day = 1)
    	{
    		_year = year;
    		_month = month;
    		_day = day;
    	}
    
    	void print()
    	{
    		cout << _year << "-" << _month << "-" << _day << endl;
    	}
    	
    	Date& operator=(const Date& d1)
    	{
    		this->_year = d1._year;
    		this->_month = d1._month;
    		this->_day = d1._day;
    		return *this;
    	}
    private:
    	int _year;
    	int _month;
    	int _day;
    };
    
    int main()
    {
    	Date d1(2019, 5, 14);
    	Date d2;
    	d2 = d1;
    	d2.print();
    }
    

    输出结果为:2019,5,14

    注意:和拷贝构造函数一样,编译器默认生成的赋值运算符重载不能用以深拷贝,否则会导致程序崩溃

    代码演示:

    #define _CRT_SECURE_NO_WARNINGS
    #include<iostream>
    #include<stdlib.h>
    
    using std::cout;
    using std::endl;
    
    class string
    {
    public:
    	string(const char* string = "hello world")
    	{
    		_str = (char*)malloc(strlen(string) + 1);
    		strcpy(_str, string);
    	}
    
    	void print()
    	{
    		cout <<_str<< endl;
    	}
    
    	~string()
    	{
    		free(_str);
    		_str = NULL;
    	}
    	/*
    	如果没有自己传建一个深拷贝的赋值运算符重载,程序就会崩溃
    	string& operator=(const string& str1)
    	{
    		_str = (char*)malloc(strlen(str1._str) + 1);
    		strcpy(_str, str1._str);
    		return *this;
    	}
    	*/
    private:
    	char* _str;
    };
    
    int main()
    {
    	string str1("hello");
    	string str2;
    	str2 = str1;
    	str2.print();
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值