深入理解C++对象模型之拷贝构造函数

一、前言

    如果一个Class没有声明一个copy constructor,编译器就会隐式声明一个copy constructor,只有编译器需要的时候,编译器才会定义一个copy constructor实例,并合成于程序之中,而编译器需要的时候是指Class不展现出bitwise copy semantics(位逐次拷贝)即“如果一个Class未定义出copy constructor,编译器就会自动为它产生出一个”这句话是不对的,只有当Class不展现出bitwise copy semantics时编译器才会产生一个。


二、拷贝构造函数

    首先这里列出C++Primer中关于拷贝构造函数的定义:如果一个构造函数的第一个参数是自身类类型的引用,且任何额外参数都有默认值,则次构造函数就是拷贝构造函数。即当一个Class object以另一个同类实例作为初始值,则这个object会调用它的copy constructor,以下三种情况,会以一个object的内容作为另一个Class object的初值:

(1)显式的“=”号初始化

(2)object作为函数的实参

(3)object作为函数的返回值

    也就是说,如果Class定义了一个copy constructor,那么以上三种情况都会调用这个copy constructor,那要是用户没有给Class定义一个copy constructor,编译器是否会合成一个呢?这是由Class的“bitwise copy semantics”决定的,如果class不展现bitwise copy semantics属性,则编译器不会合成copy constructor,如果编译器展现出bitwise copy semantics属性,那么编译器就会合成出一个copy constructor。


三、不展现bitwise copy semantics(即编译器要合成copy constructor)

(1)当class内含一个member class,而后者class声明有一个copy constructor时(不论是被class设计者显示声明或是编译器合成)

(2)继承体系中,基类含有copy constructor,而派生类没有,则编译器需要为派生类合成copy constructor

(3)含有虚函数的class(当编译器导入一个虚函数指针到一个class之中时,该class就不再展现bitwise copy semantics了)

(4)继承体系中有虚基类,则编译器需要为派生类合成copy constructor

其中第(1)(2)两种情况好理解(因为要拷贝本类,必须要先拷贝基类部分和成员类对象部分),主要在第(3)(4)两种情况,下面将详细解析。


四、含有虚函数的class

    如果一个类含有虚函数,则在编译期间,这个class需要被扩张:(1)增加一个虚函数表,表内包含每一个有作用的虚函数的地址;(2)为每一个class object安插一个指向虚函数表的指针。也就是说,class的object内存模型中就多了一个虚函数表指针的成员,请注意,一旦有了指针成员,执行bitwise copy semantics就要小心了,这会照成很多问题,一种常见的就是浅拷贝问题,当然这不是这篇文章的讨论重点,读者可以自行查阅相关资料。

    首先,要明确,在这种情况下(class 含有虚函数),编译器合成一个copy constructor的目的是重新设定在对象拷贝过程中的虚函数表指针的值,使其指向正确的虚函数表。这里分为两种拷贝情形:(1)不涉及类型交叉的对象拷贝,即同类型对象拷贝,如父类的一个对象以其另一个对象作为初值,子类的一个对象也以其另一个对象作为初值;(2)有类型交叉的拷贝,即继承体系中不同层次的对象拷贝,如父类的一个对象以子类的一个对象作为其初值。在这两种情形中,第一种情况可以直接由bitwise copy semantics完成,因为一个Class只有一个虚函数表,其两个object之间的虚函数表指针可以相互进行位逐次拷贝,这是安全的,即编译器不需要合成copy constructor。但是第二种情形就需要编译器合成的copy constructor,因为子类和父类的虚函数表不同,其各自object之间的虚函数表指针不能进行bitwise copy semantics,这是不安全的,那么编译器合成出来的copy constructor的任务就是重新设定父类的虚函数表指针,使其指向自己的(父类)虚函数表。


五、继承体系中有虚基类

    一个class object如果以另一个object 作为初值,而后者有一个虚基类部分(即其继承于虚拟基类),则就会使bitwise copy semantics失效,编译器需要合成一个copy constructor。

    同样的,类似于含有虚函数的class,即使继承体系中有虚基类,不涉及类型交叉的对象拷贝时,bitwise copy semantics仍然是有效的。使itwise copy semantics失效的仍然是有类型交叉的拷贝,即“父类的object以其子类的object作为初值时”,这时编译器需要合成一个copy constructor来设定父类对象中虚基类部分的指针或者位置偏移的初值(virtual base class pointer/offset初值)


六、总结

    与编译器合成的default constructor不同,编译器合成的copy constructor需要完成所有data member的copy工作,不像合成的default constructor只完成自己该完成的初始化工作,而不管那些需要有程序员来完成的工作。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值