构造函数语义学之Copy Constructor构建操作(1)

来源:互联网 发布:mysql定时任务 编辑:程序博客网 时间:2024/05/17 02:36

一、Copy Constructor的构建操作

  就像default constructor一样,如果class没有申明一个copy constructor,就会隐含的声明或隐含的定义一个。生成的copy constructor也分为trivial和nontrivial两种。只有nontrivial的实体才会被合成于程序之中。决定一个copy constructor是否为trivial的标准在于class是否展现出所谓的"bitwise copy semantics(语义上位逐次拷贝)"---展现出了就是trivial没的话就是nontrivial!那么什么是bitwise copy semantics,稍后会讲到。

  有四种情况下不要Bitwise Copy semantics,其实是和生成nontrivial default constructor类似啦:

  1.当class内含一个 member object 而后者的class 声明有一个 copy constructor时(不论是被class设计者明确地声明,还是背编译器合成)。

  2.当class继承自一个base class 而后者存在有一个copy constructor时(再次强调,不论被声明伙食被合成而得)。

  3.当声明一个或多个virtual functions时。

  4.当class派生自一个继承串链,其中有一个或多个virtual base classes时。

  综合是否生产nontrivial的default constructor和copy constructor的条件可看出:如果编译要做额外的事那么就需要生成nontrivial的default constructor和copy constructor!

  现在来说说什么是:bitwise copy semantics !请看一个程序:

 

 1 #include <iostream> 2 #include <string> 3  4 using namespace std; 5  6 class A  7 { 8 public: 9     int i;10     int *pi;11 };12 13  int main()14  {15     A a;16     int i = 5;17     a.i = 0;18     a.pi = &i;19     A b = a;20     cout << "a.i: " << a.i << " b.i: " << b.i << endl;21     cout << "a.pi address: " << a.pi << endl;22     cout << "b.pi address: " << b.pi << endl;23     return 0;24  }

  下面是输出结果!

  嗯,大家看到没,我的class A中没有任何和复制有关的代码,但是我在进行赋值操作 A b = a;后,b中的i 和 pi变量内的内容一模一样了,很显然:编译器在背后做了动作帮你把a的值复制给了b,这就是我要说的bitwise copy semantics(语义上位逐次拷贝)---他将 a 中的 i 所在的内存中的内容 和 pi 本身所在的内存中的内容(注意我这里说的是pi本身所在的内存中的内容而不是pi所指的内存中的内容,请区别这两个意思)逐一的拷贝给 b 中的 i 所在的内存和 pi 本身所在的内存。位逐次拷贝因此得名!!!

  数值型的 i 是正确的复制了但是指针型的 pi 就不对了,他们所指向的地址居然相同,这显然不对!这和我们所期望的不一致,对吗?你肯定是想让b中的pi 指向另外一块内存,只是这内存中的值和a 中的pi所指向的内存中的值一样罢了。并不是让指针本身相同!所以,bitwise copy (semantic我稍后解释)还有另外一个名字:浅拷贝。顾名思义,编译器只是机械的、做一些简单的拷贝!当然与bitwise copy(浅拷贝)相对应的是 memberwise(深拷贝)---这个也故名思议了,能达到你想要的效果,但是这个要你自己通过代码去实现!

  注意了哈:下面是我在看《深度探索C++对象模型》第二章copy constructor的构建时比较迷惑的地方,不知道大家有没有和我同样的疑惑呢,具体疑惑如下:

  书上给出了 Bitwise Copy Semantics的四个条件,就是我上面所说的哈!也就是不生成一个nontrivial copy constructor的条件!好,那么请看下面代码!

 1 #include <iostream> 2 #include <string> 3  4 using namespace std; 5  6 class A0 7 { 8 public: 9     A0(){}10     A0(const A0&){}11 };12 13 class A 14 {15 public:16     int i;17     int *pi;18     A0 a0;19 };20 21  int main()22  {23     A a;24     int i = 5;25     a.i = 0;26     a.pi = &i;27     A b = a;28     cout << "a.i: " << a.i << " b.i: " << b.i << endl;29     cout << "a.pi address: " << a.pi << endl;30     cout << "b.pi address: " << b.pi << endl;31     return 0;32  }

 

  这个代码只是在A的前面定义了另一个类A0,然后A类中有一个 member object a0!大家来看看class A是否符合以上4个条件中的条件 1 呢(class A的member object a0的class声明了一个 copy constructor)?那是不是不出现 bitwise copy semantic 呢?但是 i 和 pi 确实也拷贝过来了啊---看看运行结果就知道,结果和上面截图一样我就不贴出来了!这是为什么呢----这就是我迷惑的地方!那么我讲讲我的想法。

  也就是说满足以上四个条件之后进行的拷贝也进行了拷贝,只是这次不是从语义上(semantic)的copy constructor来进行拷贝了!而是从实际的copy constructor函数体中进行了拷贝,什么叫概念上?就是说之前那个class A进行的拷贝并没有合成一个nontrivial copy constructor来专门进行这个拷贝工作,所以说只是语义上(semantic)的!也就是说他确实是拷贝了,但不是通过合成那个nontrivial copy constructo来进行拷贝,我们把这种拷贝成为bitwise copy semantic!所以第二代吗中的class A 虽然满足了以上四个条件并进行了同样的bitwise copy,但这不能叫bitwise copy semantic,顶多只能叫bitwise copy啦!因为他合成了一个专门的nontrivial copy constructor,就不能叫语义上(semantic)了!

  如果大家理解了我说的那么相信大家在看《深度探索C++对象模型》第二章的copy constructor的构建操作时就不会那么迷茫了! 

 

0 0
原创粉丝点击