拷贝构造与copy assignment操作符总结

版权声明:转载请注明出处,谢谢!!! https://blog.csdn.net/qhdhnbd110/article/details/83012271

1. 一般用法

一般情况下,当需要时,一个类中会包含编译器产生的四个默认函数:

class EmptyClass
{
    EmptyClass(){}
    ~EmptyClass(){}
    EmptyClass(const EmptyClass &Copy){/*一系列的赋值操作*/}
    EmptyClass &operator=(const EmptyClass &Copy){/*一系列的赋值操作*/}
};

其中拷贝构造与copy assignment操作符只是简单的将来源对象的每一个non-static成员拷贝到目标对象。

#include <iostream>
using namespace std;
class TestClass
{
public:
	TestClass(int a, double b):x(a), y(b)
	{
	}
	~TestClass(){}
public:
	int x;
	double y;
};
int main()
{
	TestClass ObjectA(3, 1.2);
	TestClass ObjectB(ObjectA);//默认的拷贝构造
	ObjectA = ObjectB;//默认的copy assignment操作符
	cout << "ObjectA:" << ObjectA.x << " " << ObjectA.y << endl;
	cout << "ObjectB:" << ObjectB.x << " " << ObjectB.y << endl;
	return 0;
}

运行结果:

2. 浅拷贝

以上简单的将来源对象的每一个non-static成员拷贝到目标对象的拷贝动作就是浅拷贝,浅拷贝可能会带来一些问题:

#include <iostream>
using namespace std;
class TestClass
{
public:
	TestClass()
	{
		p = new int(1234);
	}
	~TestClass()
	{
		delete p;
        p = NULL;
	}
public:
	int *p;
};
int main()
{
	TestClass *ObjectA = new TestClass;
	TestClass *ObjectB = new TestClass;
	*ObjectB = *ObjectA;
	cout << "delete对象A前" << endl;
	cout << ObjectA->p << ": " << *(ObjectA->p) << endl;
	cout << ObjectB->p << ": " << *(ObjectB->p) << endl;
	delete ObjectA;
	cout << "delete对象A后" << endl;
	cout << ObjectB->p << ": " << *(ObjectB->p) << endl;
	return 0;
}

此时,ObjectA和ObjectB中的指针p均指向同一位置,当一个对象被释放时,指针p所指向的内存位置也会被操作系统回收,那么另一个对象可能就会对该内存位置非法操作(用拷贝构造初始化结果一样,在此不再演示)。

解决方法:深拷贝(即重载拷贝构造或者copy assignment操作符)

#include <iostream>
using namespace std;
class TestClass
{
public:
	TestClass()
	{
		p = new int(1234);
	}
	~TestClass()
	{
		delete p;
        p = NULL;
	}
	TestClass(const TestClass&Temp)//重载拷贝构造
	{
		this->p = new int(*(Temp.p));
   	}
        TestClass &operator=(const TestClass&Temp)//重载copy assignment操作符
	{
		this->p = new int(*(Temp.p));
                return *this;
	}
public:
	int *p;
};
int main()
{
	TestClass *ObjectA = new TestClass;
	TestClass *ObjectB = new TestClass;
	*ObjectB = *ObjectA;
	cout << "delete对象A前" << endl;
	cout << ObjectA->p << ": " << *(ObjectA->p) << endl;
	cout << ObjectB->p << ": " << *(ObjectB->p) << endl;
	delete ObjectA;
	cout << "delete对象A后" << endl;
	cout << ObjectB->p << ": " << *(ObjectB->p) << endl;
	return 0;
}

 这样,即使其中一个对象被释放,也不会出现非法访问内存的情况。

3. 拷贝构造可以而copy assignment操作符不可的情况(参考effective c++)

#include <iostream>
#include <string>
using namespace std;
class TestClass
{
public:
	TestClass(int x, std::string &hehe):SomeValue(x), SomeString(hehe)
	{
	}
	~TestClass(){}
public:
	const int SomeValue;
	std::string &SomeString;
};
int main()
{
	std::string hehe("hehe");
	std::string haha("haha");
	//默认拷贝构造方法
	TestClass A(2, hehe);
	TestClass B(A);
	//不包含<string>无法输出
	std::cout << B.SomeString << endl;
	std::cout << B.SomeValue << endl;
	//默认copy assignment操作符
	/*TestClass A(2, hehe);
	TestClass B(3, haha);
	A = B;*/
	return 0;
}

输出结果没什么问题

将拷贝构造方式注释掉,用一下copy assignment操作符,发现直接报错了:

结论:当采用拷贝构造函数时,相当于用A的成员变量的值去初始化B的成员变量,而const和reference都是需要初始化的;

           当采用copy assignment操作符时,相当于A和B初始化后又对B对象的成员变量重新赋值,而const和reference为不可修改的左值。

注意:以下方式并不是利用copy assignment操作符:

TestClass B = A;

这相当于拷贝构造函数。

猜你喜欢

转载自blog.csdn.net/qhdhnbd110/article/details/83012271