深拷贝和浅拷贝

来源:互联网 发布:无锡房价 知乎 编辑:程序博客网 时间:2024/05/19 23:57

c++编译器默认情况下会生成拷贝构造函数和赋值操作符用于新对象的构造和赋值。拷贝构造函数和赋值操作符分为两种:位拷贝(bitwise copy)和成员拷贝(member copy)。当c++类不展现bitwise copy semantic时不会按照默认的Bitwise copy,以下四种情况不展现bitwise copy semantic

1)如果一个类没有拷贝构造函数,但是含有一个类类型的成员变量,该类型含有拷贝构造函数(不管是默认的还是自己提供的),此时编译器会为该类合成一个拷贝构造函数;
2)如果一个类没有拷贝构造函数,但是该类继承自含有拷贝构造函数的基类,此时编译器会为该类合成一个拷贝构造函数;
3)如果一个类没有拷贝构造函数,但是该类声明或继承了虚函数,此时编译器会为该类合成一个拷贝构造函数;
4)如果一个类没有拷贝构造函数,但是该类含有虚基类,此时编译器会为该类合成一个拷贝构造函数;

以继承虚函数为例,以下代码没有显式实现拷贝构造和赋值操作符

#include "stdafx.h"#include <iostream>#include <string>using namespace std;// not impelement copy assignment operator and copy constructor class CBase{public:CBase(){}/*CBase(const CBase& rhs){cout << "CBase(const CBase& rhs)" << endl;memcpy(this, &rhs, sizeof(rhs));}CBase& operator = (const CBase& rhs){cout << "CBase& operator = (const CBase& rhs)" << endl;memcpy(this, &rhs, sizeof(rhs));return *this;}*/virtual void func(){cout << "Base::func()" << endl;}};class CDerived : public CBase{public:virtual void func(){cout << "CDerived::func()" << endl;}};typedef void (*func)();int _tmain(int argc, _TCHAR* argv[]){CBase b = CBase();CDerived d = CDerived();cout << "b vtable address: " << *(int*)(&b) << endl;cout << "d vtable address: " << *(int*)(&d) << endl;b = d;cout << "b vtable address: " << *(int*)(&b) << endl;func(*(int*)*(int*)(&b))();CBase b1 = CDerived();func(*(int*)*(int*)(&b1))();return 0;}
运行结果:

b vtable address: 20109928d vtable address: 20109968b vtable address: 20109928Base::func()Base::func()Press any key to continue . . .
可以看到,基类的虚函数表地址没有被以浅拷贝(bitwise copy)的方式被子类的虚函数表地址所覆盖,而是reset为基类的虚函数表地址,说明编译器默认合成的拷贝构造函数和赋值操作符显式地指定了vptr到基类的virtual table。
另外,以下代码显式实现拷贝构造和赋值操作符

#include "stdafx.h"#include <iostream>#include <string>using namespace std;// impelement copy assignment operator and copy constructor class CBase{public:CBase(){}CBase(const CBase& rhs){cout << "CBase(const CBase& rhs)" << endl;memcpy(this, &rhs, sizeof(rhs));}CBase& operator = (const CBase& rhs){cout << "CBase& operator = (const CBase& rhs)" << endl;memcpy(this, &rhs, sizeof(rhs));return *this;}virtual void func(){cout << "Base::func()" << endl;}};class CDerived : public CBase{public:virtual void func(){cout << "CDerived::func()" << endl;}};typedef void (*func)();int _tmain(int argc, _TCHAR* argv[]){CBase b = CBase();CDerived d = CDerived();cout << "b vtable address: " << *(int*)(&b) << endl;cout << "d vtable address: " << *(int*)(&d) << endl;b = d;cout << "b vtable address: " << *(int*)(&b) << endl;func(*(int*)*(int*)(&b))();CBase b1 = CDerived();func(*(int*)*(int*)(&b1))();return 0;}
运行结果:
b vtable address: 20634216d vtable address: 20634284CBase& operator = (const CBase& rhs)b vtable address: 20634284CDerived::func()CBase(const CBase& rhs)CDerived::func()Press any key to continue . . .
可以看到,当我们显示的实现拷贝构造和赋值操作符并在其中进行浅拷贝操作后,成功地将虚函数指针指向了之类的虚函数表。






原创粉丝点击