二、详述条件 3 和 4

  那么好,我又要问大家了,条件1 和 2比较容易理解。因为member object或 base class 含有copy constructor。那么member object所在的class或者base class的derived class需要合成一个nontrivial copy constructor来调用他的member constructor 或 base class的 copy constructor!

  而条件 3 和条件 4比较难理解,我在此阐述一下:

  (1) 条件3:当声明一个或多个virtual functions时

    大家回忆一下,在满足条件 3 时(class 声明了至少一个 virtual function),编译期间的两个程序扩张操作!

    1).增加一个virtual function table ,内涵每一个有作用的function的地址。

    2).将一个指向 virtual function table 的指针(vptr),安插在每一个class object 内。

  好,下面看我一个程序:

 #include <iostream>
#include <string>
using namespace std; class A0
{
public: virtual void fun(){ cout << "I belong to A0!" << endl;}
}; class A: public A0
{
public:
virtual void fun(){ cout << "I belong to A!" << endl;}
}; int main()
{
19 A a;20
20     A b = a;
     return ;
}

  大家看看代码中的第 20 行是不是将 a 赋值给了b,那么 a 中的指针 vptr 是不是 bitwise copy 给了 b 的指针 vptr 呢?答案是肯定的!但是这回指针的bitwise copy 是安全滴。为什么呢?因为同一类型的类实体中的 vptr 在内存中本身就是共享同一个 virtual function table的,请看下面一个图!

    图1 :这张补充说明了程序中 a 和 b 的关系,

  说到这里大家肯定要说了,这个用 bitwise copy semantic 完成不就可以了?为什么还要合成一个copy constructor来完成呢?对,如果仅仅是对付上面代码 bitwise copy semantic 足矣,但是我把上面代码中的main函数中的内容变一下:、

 #include <iostream>
#include <string>
using namespace std; class A0
{
public:

9 virtual void fun(){ cout << "I belong to A0!" << endl;}
}; class A: public A0
{
public:
virtual void fun(){ cout << "I belong to A!" << endl;}
}; int main()
{
A a;
A0 a0 = a;
A0 *pa0;
pa0 = &a;
pa0->fun();
pa0 = &a0;
pa0->fun();
return ;
}

  运行结果大家自己测试,如果此时,还是仅仅通过简单的 bitwise copy semantic 的话。那第 24 行中的pa0->fun()将会调用的是 a 的 fun() 输出,I belong to A! 这显然已经不满足类的多态性了嘛!说到这想必大家已经猜到一二了吧?对,此时编译器对类 A0 的对象不能bitwise copy semantic了,而是合成一个copy constructor进行一些必要的操作:包括对程序员定义的 member 的 bitwise copy (浅拷贝)和 对编译器安插的 vptr 进行重新赋值,即指向子类上例中的 A0 class 的 virtual table!很难理解?请看下图:

      图2 :补充说明 a0 和 a 的关系

  对比一下图 1 和图 2,就知道为什么 bitwise copy semantic不行了,而必须要合成一个copy constructor进行进一步操作了吧?

  (2)条件4---当class派生自一个继承串链,其中有一个或多个virtual base classes时

  如果你看懂了,条件 3 那么条件 4 这个也能很快就懂了!大家还记不记得我在我的另一篇博文(构造函数语义学之Default Constructor构建操作)中讲到 virtual base class时讲到:“编译器会为虚继承的derived class中安插一个指针 (vbptr)---用来指向virtual base class pointer table,这个表用来描述从继承类元素到虚基类元素的偏移量。”,既然如此,这和条件3是不是很像呢?也是安插了一个指针,那是不是也不能要bitwise copy constructor 呢?答案是肯定的!因为,这个 vbptr 指针 以及 virtual base class pointer table在内存中如何布局我们还没讲到,这里大家只要知道编译器安插了一个指针,该指针在复制时不能简单的 bitwise copy constructor就行了。剩下的,我会在后来的博文中阐述清楚!

构造函数语义学之Copy Constructor构建操作(2)的更多相关文章

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

    一.Copy Constructor的构建操作 就像 default constructor 一样,如果class没有申明一个 copy constructor,就会隐含的声明或隐含的定义一个.生成的 ...

  2. 构造函数语义学之Default Constructor构建操作

    一.Default Constructor的构建操作 首先大家要走出两个误区: 1).任何class如果没有定义default constructor,就会被合成一个来. 2).便以其合成出来的def ...

  3. 深度探索C++对象模型之第二章:构造函数语意学之Copy constructor的构造操作

    C++ Standard将copy constructor分为trivial 和nontrivial两种:只有nontrivial的实例才会被合成于程序之中.决定一个copy constructor是 ...

  4. 构造函数语义学——Copy Constructor 的构造操作

    前言 在三种情况下,会以一个 object 的内容作为另一个 class object 的初值: object明确初始化 class X{...}; X x; X xx = x; object 被当作 ...

  5. 构造函数语义学——Copy Constructor 篇

    构造函数语义学--Copy Constructor 篇 本文主要介绍<深度探索 C++对象模型>之<构造函数语义学>中的 Copy Constructor 构造函数的调用时机 ...

  6. C++ 类 复制构造函数 The Copy Constructor

    一.复制构造函数的定义 复制构造函数是一种特殊的构造函数,具有一般构造函数的所有特性.复制构造函数创建一个新的对象,作为另一个对象的拷贝.复制构造函数只含有一个形参,而且其形参为本类对象的引用.复制构 ...

  7. 构造函数语义学——Default Constructor篇

    构造函数语义学--Default Constructor 篇 这一章原书主要分析了:编译器关于对象构造过程的干涉,即在对象构造这个过程中,编译器到底在背后做了什么 这一章的重点在于 default c ...

  8. 深度探索C++对象模型之第二章:构造函数语意学之Default constructor的构造操作

    C++新手一般由两个常见的误解: 如果任何class没有定义默认构造函数(default constructor),编译器就会合成一个来. 编译器合成的的default constructor会显示的 ...

  9. Copy Constructor的构造操作

    Copy Constructor的构造操作 有三种情况,会以一个object的内容作为另一个class object的初值: 1.  对一个object做显式的初始化操作 class X{…}; X ...

随机推荐

  1. qt 状态栏

    有段时间没有写过博客了.假期去上海旅游,所以一直没有能够上网.现在又来到这里,开始新的篇章吧!   今天的内容主要还是继续完善前面的那个程序.我们要为我们的程序加上一个状态栏.   状态栏位于主窗口的 ...

  2. java中的mmap实现--转

    什么是mmap mmap对于c程序员很熟悉,对于java程序员有点陌生.简而言之,将文件直接映射到用户态的内存地址,这样对文件的操作不再是write/read,而是直接对内存地址的操作. 在c中提供了 ...

  3. iOS RSA 加密解密及签名验证

    1.首先要下载openssl.这个不用说,直接官网下载或者用brew install openssl下载. 2.终端生成私钥密钥. 2.1生成私钥 openssl genrsa - 2.2生成密钥 o ...

  4. svn 设置钩子将代码同步到web目录下面

    首先:确定思路: 要在SVN服务中,找到仓库文件夹的位置,在相应的项目中找到hooks文件夹.在该文件中添加一个post-commit文件: 当有commit动作发生时(提交到SVN服务是就会执行这个 ...

  5. Java_Activiti5_菜鸟也来学Activiti5工作流_之入门简单例子(一)

    // VacationRequest.java /** * author : 冯孟活 ^_^ * dates : 2015年9月1日 下午10:32:58 * class : 演示简单的公司请假流程 ...

  6. SQLServer 触发器----增删改触发,两张表

    ALTER TRIGGER [dbo].[PriceRange]   ON  [dbo].[Tab_SaleAndCarStyle]   for update,insert,deleteASdecla ...

  7. jQuery注册验证

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. 设置linux服务器定时与时间服务器同步

    在一些大公司经常出现这样一个情况:公司或一些机关单位的内部业务系统的应用服务器以及数据都是做的多机集群部署而且基本都是linux系统,而且都是内部网,不与外网通讯的.这样经常就会出现一个情况,我发送任 ...

  9. C# div、css

    目录: 1.Div+Css布局教程(-)CSS必备知识 注:本教程要求对html和css有基础了解. 一.CSS布局属性 Width:设置对象的宽度(width:45px). Height:设置对象的 ...

  10. [转]Delphi中ShellExecute的妙用

    Delphi中ShellExecute的妙用       ShellExecute的功能是运行一个外部程序(或者是打开一个已注册的文件.打开一个目录.打印一个文件等等),并对外部程序有一定的控制.   ...