C++ 编程规范-拷贝构造函数和拷贝赋值运算符

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

1. 普通情况下,拷贝构造和拷贝赋值运算符的书写

  1. 注意
    在默认情况下(用户没有定义,但是也没有显示的删除),编译器会自动隐式生成一个拷贝构造函数和赋值运算符,但用户可以使用delete来指定不生成拷贝构造函数和赋值运算符,这样的对象就不能通过值传递,也不能进行赋值运算。

需要注意的是,拷贝构造函数必须以引用的方式传递参数,这是因为,在值传递给一个函数的时候,会调用拷贝构造函数生成函数的实参,如果拷贝构造函数的参数仍然是以值的方式,就会无限循环的调用下去,直到函数的栈溢出。

void func(alpha);  //以值传递对象
func(a1);      //函数调用

这时a1的拷贝构造函数将会被调用来创建一个对象a1的副本,并将副本交给函数func()操作。(当然引用或者指针就不会调用拷贝构造函数)

  1. 区别
    拷贝构造函数和赋值运算符的行为比较相似,都是将一个对象的值复制给另一个对象,但是其结果却有些不同,拷贝构造函数使用传入对象的值生成一个新的对象的实例,而赋值运算符是将对象的值复制给一个已经存在的实例。这种区别从两者的名字也能轻易的分辨出来,拷贝构造函数也是一种构造函数,那么它的功能就是创建一个新的对象实例;赋值运算符是执行某种运算,将一个对象的值复制给另一个对象(已经存在的)。调用的是拷贝构造函数还是赋值运算符,主要是看是否有新的对象实例产生,如果产生了新的对象实例,那调用的就是拷贝构造函数;如果没有,那就是对已有的对象赋值,调用的是赋值运算符。

  2. 延伸:this指针
    每一个对象的成员函数都可以访问一种神奇的指针,即指向该对象本身的this指针,因而在任何对象中都可找到所属对象的自身地址。拷贝赋值构造函数中使用this指针作为返回值,指的就是被赋值的对象本身。
    需要注意,this指针在静态成员函数中是无效的,因为静态成员函数不属于任何特定的对象。

namespace _nmsp1
{
	class A {
		A(): m_caa(0), m_cab(0), m_cap(new char[100]) {} // 构造函数
		// A(const A& tmpobj) = delete;  //可以删除默认的拷贝构造函数
		~A()
		{
			delete [] m_cap;
		}
		A(const A& tmpobj)  //拷贝构造函数
		{
			// 拷贝构造函数有新的对象实例产生。m_cap首先分配内存,然后将要拷贝的值赋给m_cap
			m_cap = new char[100];   
			memcpy(m_cap, tmpobj.m_cap, 100);
			
			m_caa = tmpobj.caa;
			m_cab = tmpobj.cab;
		}	
		// A& operator= (const A& tmpobj) = delete;  //可以删除默认的拷贝赋值运算符
		A& operator= (const A& tmpobj)  //赋值构造函数
		{
			// 防止自我赋值
			if(this == &tmpobj)
			{
				return *this;
			}
			
			// 复制构造函数没有新的对象产生,原来已经有对象了,所以需要先删除原来的动态数组。
			delete [] m_cap;  // 如果只调用delete m_cap,那么只会删除数组的第一个数据
			m_cap = new char[100];
			memcpy(m_cap, tmpobj.m_cap, 100);
			
			m_caa = tmpobj.caa;
			m_cab = tmpobj.cab;
			return *this;  // 指向该成员函数所属的对象
		}
	}
	public:
		int m_caa;
		int m_cab;
		char* m_cap;   //指向定长100的字符;
}

int main()
{
	_nmsp1::A aobj1;
	aobj1.m_caa = 10; aobj1.m_cab = 20;
	_nmsp1::A aobj2(aobj1);  //调用拷贝构造函数
	_nmsp1::A aobj4 = aobj1;  // 调用拷贝构造函数,因为有新的类对象实例产生
	_nmsp1::A aobj3; 
	aobj3 = aobj1;  //调用拷贝赋值构造法
}

2. 继承关系下,拷贝赋值运算符和拷贝构造函数的书写

如果在子类中写了拷贝构造函数和拷贝赋值运算符,那么对于父类中的拷贝构造函数和拷贝赋值运算符,需要程序员自己调用,否则会调用子类自己的拷贝构造函数和拷贝赋值运算符。

class C : public A
{
public:
	C() {};
	C(const C& tmpobj):A(tmpobj)  // 拷贝构造函数,调用父类的拷贝构造函数
	{
	}
	C& operator= (const C& tmpobj)  // 拷贝赋值运算符
	{
		A::operator= (tmpobj);  // 调用父类的拷贝赋值运算符
		return *this
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值