深度探索C++对象模型-语意学

  有三种情况,会以一个object的内容作为另一个class object的初值:
           
Cpp代码   收藏代码
  1. class X { ... };  
  2. X x;  
  3.   
  4. X xx = x;               // 情况1,赋值对象  
  5.   
  6. extern void foo( X x);  
  7.   
  8. void bar()  
  9. {  
  10.      
  11.     X xx;  
  12.   
  13.     foo( xx );         // 情况2,作为参数  
  14.   
  15. }  
  16.   
  17. X foo_bar()  
  18. {  
  19.   
  20.     X xx;  
  21.   
  22.     return xx;         // 情况3,作为返回值  
  23. }  

    
               
        Default Memberwise Initalization

            如果class 没有提供一个explicit copy constructor又当如何?当class object 以 “相同class的另一个object”作为初值时,其内是以所谓的default memberwise initalization手法完成的,也就是把每一个内建的或派生的data member的值,从某个object拷贝一份到另一个object身上。不过它不会拷贝其中的member class object, 而是以递归的方式实行memberwise initalization.
           
            例子:

Cpp代码   收藏代码
  1. class String  
  2. {  
  3.   
  4.     public:  
  5.      
  6.         //..没有explicit copy constructor  
  7.   
  8.     private:  
  9.   
  10.         char *str;  
  11.         int   len;  
  12.      
  13. };             
  14.   
  15. class Word  
  16. {  
  17.     public:  
  18.      
  19.         //..没有explicit copy constructor  
  20.     private:  
  21.   
  22.         int _occurs;  
  23.         String _word;  //String object成为class word的一个member. 此处以递归的方式实行memberwise initalization.  
  24.                   // Word 是否合成 copy constructor 取决于 bitwise copy semantics.  
  25.                 //此例子不合成copy constructor 编译器会自动复制每一个数据成员  
  26. };  

 
                指出一个错误概念:“如果一个class未定义copy constructor,编译器就自动为它产生出一个”这句话不对
                正确的概念:Default constructor 和 copy constructor在必要的时候才由编译器产生出来。“必要”意指当class不展现bitwise copy semantics时。

        Bitwise Copy Semantics(位逐次拷贝)

            上例展示了Bitwise copy Semantics.

            有一点很值得注意:在被合成出来的copy constructor中,如整数、指针、数组等等的nonclass memebers也都会被复制,正如我们所期待的一样。   

        不要Bitwise Copy Semantics
       
            有四种情况不展示Bitwise Copy Semantics, 不展示的时候需要编译器合成copy constructor:

                (1)当class内含一个member object而后者的class声明有一个copy constructor时
                (2)当class继承自一个base class 而后者存在有一个copy constructor时
                (3)当class声明了一个或多个virtual functions时
                (4)当class派生自一个继承串链,其中有一个或多个virtual base classes时

        结论:如果是自定义复制构造函数时,需要自己把每一个数据成员复制;如果是没有自定义复制构造函数,无论是合成或非合成,编译器都会自动复制每一个数据成员。复制构造函数的用途是:如果构造函数中存在动态内存分配,则必须定义复制构造函数,否则会出现“指针悬挂问题”。

Cpp代码   收藏代码
  1. class A  
  2. {  
  3.     private:  
  4.         int *p;  
  5.   
  6.     public:  
  7.         A()  
  8.         {  
  9.             p = new int(3);  
  10.         }  
  11. };      

 
       
        在这种情况下,复制对象,会造成两个对象的成员指向同一地址。

        重新设定Virtual Table的指针
   
            例子:

Cpp代码   收藏代码
  1. class ZooAninal  
  2. {  
  3.     public:  
  4.         ZooAnimal();  
  5.         virtual ~ZooAnimal();  
  6.   
  7.         virtual void animate();  
  8.         virtual void draw();         
  9. };  
  10.   
  11. class Bear : public ZooAnimal()  
  12. {  
  13.      
  14.     public:  
  15.         Bear();  
  16.         void animate();  
  17.         void draw();     
  18.         virtual void dance();  
  19.   
  20. };  
 
                Bear yogi;
                Bear winnie = yogi;

                把yogi 的vptr值拷贝给winnie的vptr是安全的

               

 

                ZooAnimal franny = yogi; // 这会发生 切割行为

               

 

                合成出来的ZooAinmal copy constructor会明确设定object的vptr指向ZooAnimal class的virtual table,而 不是直接从右手边的class object中将其vptr现值拷贝过来。
       

        处理Virtual Base Class Subobject


总结:

可以这么认为,并不是在没有自定义copy constructor的时候编译器就合成一个copy constructor,而是在没有bitwise copy semantics时会合成一个 ,在执行default memberwise initialization的时候。

并没有把这个操作当做在copy constructor的时候执行,这个操作并不认为是在copy constructor的时候完成的。这是我对这本书这一节的理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值