Inside the C++ Object Model 深度探索对象模型 1-Object, 2-Constructor
2013-03-03 22:01
537 查看
前言摘录 >BarbaraMoo常说 管理一个团队 就像放牧一群骄傲的猫.
1 关于对象Object
>参数化
加上封装后的布局成本 Layout costs for adding Encapsulation
>C++在布局和存储时间上主要的额外负担是由Virtual引起
-virtual function机制 支持一个有效率的"执行期绑定" runtime binding; -virtual base class 实现"多次出现在继承体系中的base class, 有一个单一而被共享的实体" [棱形结构] -一些多重继承下的额外负担
1.1 C++对象模式
>class data: static/nonstatic; class member functions: static/nonstatic/virtual;
简单对象模型
>一个class的大小, 指针大小乘以class中所声明的members的数目;
表格驱动对象模型
>Member Data Table+Member Function Table
C++对象模型
1)class产生一堆指向virtual functions的指针 放在virtual table里面;
2) vptr 每一个class object被添加了一个指针 指向相关的vtable, vptr的设定和重置都由每一个class的constructor和destructor,copy assignment运算符完成; 每个class关联的type_info object(RTTI)由vtable指出.
加上继承 Inheritance
>单一继承 多重继承 虚拟/共享继承 -虚拟继承的情况下 base class不管被派生多少次, 只会存在一个实体subobject.
对象模型如何影响程序
>不同的对象模型会导致'现有代码修改', '加入新的程序代码'
1.2 关键词差异 keyword distinction
关键词的困扰
>class-struct ADT(abstract data type)
策略性正确的struct
>C struct在C++中的合理用途, 当你要传递一个复杂的class object的全部或者部分到某个C函数中去时, struct可以将数据封装起来, 保证拥有与C兼容的空间布局. 这项保证只在组合composition的情况下才存在, 对于继承, 编译器会决定是否应该有额外的data members被安插到base struct subobject中.
1.3 对象的差异
>C++直接支持3种程序设计典范 programming paradigms
1) 程序模型 procedural model 2) 抽象数据模型 abstract data type ADT model 3) 面向对象模型 object oriented model
>只有通过point和reference的间接处理才支持OO设计的多态性质.
>C++支持多态的方法
1)隐含的转化操作, 把derived class指针转化为指向public base type的指针 Ex. shape* ps = new circle();
2)virtual function机制 3) dynamic_cast和typeid
>一个class object的内存 -nonstatic data members总和; -应alignment的需求填补边界padding; -支持virtual由内部产生的额外负担 overhead;
指针的类型
>指针的内存大小是固定的, 与指向的数据类型无关;
1) 指向地址1000的整数指针 在32bit机器上 地址空间1000~1003, 4byte/一个word空间; 2) 如果String是8byte, 一个4byte的字符指针和一个表示字符串长度的int. 3) ZooAnimal指针为 1000~1015(int+string+vptr 4+8+4)
加上多态
Ex. Bear b; ZooAnimal* pz = &b; Bear* pb = &b; // ((Bear*)pz)->BearMember(); pb->BearMember(); [dynamic_cast]
Ex. Bear b; ZooAnimal za = b; //切割 sliced
>当一个base class object被直接初始化为一个derived class object时, derived class object会被切割, 塞入较小的base type 内存中; 没有多态出现;
---Section1 End---
2 构造函数语意学 The Semantics of Constructors
2.1 Default Constructor的构建操作
>default constructor在需要的时候被编译器产生出来; 4种情况
带有Default Constructor的Member Class Object
>一个class没有constructor, 但它内含一个member obejct, 后者有default constructor, 那这个class的implicit default constructor是nontrivial, 编译器需要为class合成一个default constructor.
带有Default Constructor的Base Class
>一个没有constructor的class派生自一个带有default constructor的base class, 则这个derived class的default constructor会被视为nontrivial.
带有一个Virtual Function的Class
1) class声明/继承一个virtual function; 2) class派生自一个继承串链, 其中有virtual base classes.
>编译期间的扩张操作 1) virtual function table(vtbl)会被编译器产生出来, 内置class的virtual function地址. 2)在每个class object中, 额外的pointer member(vptr)会被编译器合成出来, 内含相关class vtbl地址.
带有一个Virtual Base Class的Class
>棱形继承/虚拟继承; 在derived class object的每一个virtual base class中安插一个指针; 经由reference或pointer来存取一个virtual base class的操作都可以通过相关指针完成.
总结 在合成的default constructor中只有base class subobjects和member class object会被初始化, 其他的nonstatic data member Ex. 整数 整数指针 整数数组等不会被初始化.
2.2 Copy Constructor的构建操作
>3种情况, . Ex. class X {...}; X x;
1) 明确以以一个object的内容作为另一个class object的初值: X x2 = x; 2) 当object作为参数: foo(x2); 3) 当函数传回一个class object: X foo_2() { return x2;}
>拷贝构造函数的第一个参数类型是class type, 第二参数以及后继参数需要有默认值;
Default Memberwise Initialization
>DMI把每一个内建的或派生的data member(指针,数组,etc)的值, 从某个object拷贝一份到另一个object, 不会拷贝其中的member class object, 而是以递归的方式施行memberwise initializtion.(赋值初始化)
>default constrctor和copy constructor在必要的时候才由编译器产生出来 (当class不展现bitwise copy semantics时)
>一个class object可以从两种方式复制得到, 1)被初始化-copy constructor 2)被指定 assignment -copy assignment operator.
Bitwise Copy Semantics位逐次拷贝 - 不要Bitwise Copy Semantics
一个class不展现bitwise copy semantic的情况:
1) 当class内含member object, 后者的class声明有一个copy constructor时(不论是设计者明确声明或者编译器合成的);
2)当class继承自一个base class, 后者存在有一个copy constructor时.
3)当class声明了一个或多个virtual functions时.
4)当class派生自一个继承串链, 其中有一个或多个virtual base classes时.
>前2种情况, 编译器必须将member或base class 的copy constructor调用操作安插到被合成的copy constructor中.
重新设定Virtual Table的指针
>编译期间的2个程序扩张操作 -增加一个vtbl, 内含每一个有作用的virtual function的地址; -将一个指向vtbl的指针vptr安插在每一个class object内;
>当编译器导入一个vptr到class中时, 该class就不再展现bitwise semantics了;
处理Virtual Base Class Subobject
>一个class object如果以另一个object作为初值, 而后者有一个virtual base class subobject, 会使bitwise copy semantics失效;
2.3 程序转化语意学 Program Transformation Semantics
明确的初始化操作 Explicit Initialization
>程序转换2个阶段 1)重写每个定义(占用内存的行为), 初始化操作被剥除; 2) 安插class的copy constructor操作;
X x1(x0); -->编译器安插X copy constructor的操作 X x1; x1.X::X(x0);
参数的初始化 Argument Initialization
>把一个class object当作参数传给一个函数(或作为函数的返回值), 相当于 X xx = arg; 的操作;
Ex. void foo(X x0); X xx; foo(xx); 编译器的操作--> X __temp0; __temp0.X::X(xx); foo(__temp0); //形参需要改变为reference; void foo(X& x0); 另一种实现方法是以拷贝建构copy construct的方式把实际参数直接建构在其所在位置上.(Borland C++)
返回值的初始化 Return Value Initilization
>双阶段转化 1)加上一个额外参数, 类型是class object的reference. 这个参数用来放置被拷贝构建copy constructed而得的返回值; 2)在return指令之前安插一个copy constructor调用操作, 将想要传回的object的内容当作上述新增参数的初值;
Ex. X bar() { X xx; return xx;} 编译器转换--> void bar(X& __result) { X xx; xx.X::X(); __result.X::X(xx); return;}
函数指针 X (*pf)(); pf=bar; --> void (*pf)(X&); pf=bar;
在使用者层面做优化 Optimization at the User Level
>定义一个计算用的constructor; Ex. X bar(const T& y, const T &z) { return X(y, z); } --> void bar (X& __result, const T& y, const T& z) { __result.X::X(y, z); return; }
在编译器层面做优化 Optimization at the Compiler Level
>编译器优化操作 Named Return Value(NRV)优化;
>批评1)优化由编译器完成, 实现程度外部不可知; 2)函数变得比较复杂时, 优化难以施行; 3)程序员在某些情况下不希望应用程序优化;
Ex. X xx0(1024); --> xx0.X::X(1024); //单一的constructor操作; Ex. X xx1 = X(1024); X __temp; __temp.X::X(1024), xx1.X::X(__temp); __temp.X::~X(); //调用两个constructor, 对于临时object调用destructor;
Copy Constructor 要还是不要
>default copy constructor被视为trivial, bitwise copy不会导致memory leak和address aliasing, 快速安全;
>memcpy()或memset()都只有在classes不含任何由编译器产生的内部members时才能有效运行.
摘要 copy constructor的应用 会使编译器多少对程序代码做部分转化, 当函数以传值方式传回class object, 而该class有copy constructor(明确定义或者合成出来的), 会导致程序转化--在函数的定义或使用上; 编译器也将copy constructor的调用操作优化, 以一个额外的第一参数取代NRV.
2.4 成员们的初始化队伍 Member Initialization List
>必须使用member initialization list的情况
1)初始化一个reference member; 2)初始化一个const member; 3)调用一个base class的constructor, 而它拥有一组参数时; 4) 调用一个member class的constructor, 而它拥有一组参数时;
>member initialization list提高效率, 避免编译器内部扩张constructor; Ex.
扩张-->Word::Word() { mName.string::string(); string temp = string(0); mName.string::operator=(temp); temp.string::~string(); mCnt = 0; }
>提高效率的办法 Word::Word() : mName(0) { mCnt = 0; } 扩张--> Word::Word() { mName.string::string(0); mCnt = 0; } //调用了string(0)的constructor;
Notice: >list中的初始化顺序是由class中的members的声明次序决定的, 不是initialization list的排列次序决定的. >Initialization list的操作被放在explicit user code之前;
>编译器会对initialization list处理并可能重新排序, 会安插一些代码到constructor内, 放置于explicit user code之前.
---Section2 End---
1 关于对象Object
>参数化
>C++在布局和存储时间上主要的额外负担是由Virtual引起
-virtual function机制 支持一个有效率的"执行期绑定" runtime binding; -virtual base class 实现"多次出现在继承体系中的base class, 有一个单一而被共享的实体" [棱形结构] -一些多重继承下的额外负担
1.1 C++对象模式
>class data: static/nonstatic; class member functions: static/nonstatic/virtual;
简单对象模型
>一个class的大小, 指针大小乘以class中所声明的members的数目;
表格驱动对象模型
>Member Data Table+Member Function Table
C++对象模型
1)class产生一堆指向virtual functions的指针 放在virtual table里面;
2) vptr 每一个class object被添加了一个指针 指向相关的vtable, vptr的设定和重置都由每一个class的constructor和destructor,copy assignment运算符完成; 每个class关联的type_info object(RTTI)由vtable指出.
加上继承 Inheritance
>单一继承 多重继承 虚拟/共享继承 -虚拟继承的情况下 base class不管被派生多少次, 只会存在一个实体subobject.
对象模型如何影响程序
>不同的对象模型会导致'现有代码修改', '加入新的程序代码'
1.2 关键词差异 keyword distinction
关键词的困扰
>class-struct ADT(abstract data type)
策略性正确的struct
>C struct在C++中的合理用途, 当你要传递一个复杂的class object的全部或者部分到某个C函数中去时, struct可以将数据封装起来, 保证拥有与C兼容的空间布局. 这项保证只在组合composition的情况下才存在, 对于继承, 编译器会决定是否应该有额外的data members被安插到base struct subobject中.
1.3 对象的差异
>C++直接支持3种程序设计典范 programming paradigms
1) 程序模型 procedural model 2) 抽象数据模型 abstract data type ADT model 3) 面向对象模型 object oriented model
>只有通过point和reference的间接处理才支持OO设计的多态性质.
>C++支持多态的方法
1)隐含的转化操作, 把derived class指针转化为指向public base type的指针 Ex. shape* ps = new circle();
2)virtual function机制 3) dynamic_cast和typeid
>一个class object的内存 -nonstatic data members总和; -应alignment的需求填补边界padding; -支持virtual由内部产生的额外负担 overhead;
指针的类型
>指针的内存大小是固定的, 与指向的数据类型无关;
1) 指向地址1000的整数指针 在32bit机器上 地址空间1000~1003, 4byte/一个word空间; 2) 如果String是8byte, 一个4byte的字符指针和一个表示字符串长度的int. 3) ZooAnimal指针为 1000~1015(int+string+vptr 4+8+4)
Ex. Bear b; ZooAnimal* pz = &b; Bear* pb = &b; // ((Bear*)pz)->BearMember(); pb->BearMember(); [dynamic_cast]
Ex. Bear b; ZooAnimal za = b; //切割 sliced
>当一个base class object被直接初始化为一个derived class object时, derived class object会被切割, 塞入较小的base type 内存中; 没有多态出现;
---Section1 End---
2 构造函数语意学 The Semantics of Constructors
2.1 Default Constructor的构建操作
>default constructor在需要的时候被编译器产生出来; 4种情况
带有Default Constructor的Member Class Object
>一个class没有constructor, 但它内含一个member obejct, 后者有default constructor, 那这个class的implicit default constructor是nontrivial, 编译器需要为class合成一个default constructor.
带有Default Constructor的Base Class
>一个没有constructor的class派生自一个带有default constructor的base class, 则这个derived class的default constructor会被视为nontrivial.
带有一个Virtual Function的Class
1) class声明/继承一个virtual function; 2) class派生自一个继承串链, 其中有virtual base classes.
>编译期间的扩张操作 1) virtual function table(vtbl)会被编译器产生出来, 内置class的virtual function地址. 2)在每个class object中, 额外的pointer member(vptr)会被编译器合成出来, 内含相关class vtbl地址.
带有一个Virtual Base Class的Class
>棱形继承/虚拟继承; 在derived class object的每一个virtual base class中安插一个指针; 经由reference或pointer来存取一个virtual base class的操作都可以通过相关指针完成.
总结 在合成的default constructor中只有base class subobjects和member class object会被初始化, 其他的nonstatic data member Ex. 整数 整数指针 整数数组等不会被初始化.
2.2 Copy Constructor的构建操作
>3种情况, . Ex. class X {...}; X x;
1) 明确以以一个object的内容作为另一个class object的初值: X x2 = x; 2) 当object作为参数: foo(x2); 3) 当函数传回一个class object: X foo_2() { return x2;}
>拷贝构造函数的第一个参数类型是class type, 第二参数以及后继参数需要有默认值;
Default Memberwise Initialization
>DMI把每一个内建的或派生的data member(指针,数组,etc)的值, 从某个object拷贝一份到另一个object, 不会拷贝其中的member class object, 而是以递归的方式施行memberwise initializtion.(赋值初始化)
>default constrctor和copy constructor在必要的时候才由编译器产生出来 (当class不展现bitwise copy semantics时)
>一个class object可以从两种方式复制得到, 1)被初始化-copy constructor 2)被指定 assignment -copy assignment operator.
Bitwise Copy Semantics位逐次拷贝 - 不要Bitwise Copy Semantics
一个class不展现bitwise copy semantic的情况:
1) 当class内含member object, 后者的class声明有一个copy constructor时(不论是设计者明确声明或者编译器合成的);
2)当class继承自一个base class, 后者存在有一个copy constructor时.
3)当class声明了一个或多个virtual functions时.
4)当class派生自一个继承串链, 其中有一个或多个virtual base classes时.
>前2种情况, 编译器必须将member或base class 的copy constructor调用操作安插到被合成的copy constructor中.
重新设定Virtual Table的指针
>编译期间的2个程序扩张操作 -增加一个vtbl, 内含每一个有作用的virtual function的地址; -将一个指向vtbl的指针vptr安插在每一个class object内;
>当编译器导入一个vptr到class中时, 该class就不再展现bitwise semantics了;
处理Virtual Base Class Subobject
>一个class object如果以另一个object作为初值, 而后者有一个virtual base class subobject, 会使bitwise copy semantics失效;
2.3 程序转化语意学 Program Transformation Semantics
明确的初始化操作 Explicit Initialization
>程序转换2个阶段 1)重写每个定义(占用内存的行为), 初始化操作被剥除; 2) 安插class的copy constructor操作;
X x1(x0); -->编译器安插X copy constructor的操作 X x1; x1.X::X(x0);
参数的初始化 Argument Initialization
>把一个class object当作参数传给一个函数(或作为函数的返回值), 相当于 X xx = arg; 的操作;
Ex. void foo(X x0); X xx; foo(xx); 编译器的操作--> X __temp0; __temp0.X::X(xx); foo(__temp0); //形参需要改变为reference; void foo(X& x0); 另一种实现方法是以拷贝建构copy construct的方式把实际参数直接建构在其所在位置上.(Borland C++)
返回值的初始化 Return Value Initilization
>双阶段转化 1)加上一个额外参数, 类型是class object的reference. 这个参数用来放置被拷贝构建copy constructed而得的返回值; 2)在return指令之前安插一个copy constructor调用操作, 将想要传回的object的内容当作上述新增参数的初值;
Ex. X bar() { X xx; return xx;} 编译器转换--> void bar(X& __result) { X xx; xx.X::X(); __result.X::X(xx); return;}
函数指针 X (*pf)(); pf=bar; --> void (*pf)(X&); pf=bar;
在使用者层面做优化 Optimization at the User Level
>定义一个计算用的constructor; Ex. X bar(const T& y, const T &z) { return X(y, z); } --> void bar (X& __result, const T& y, const T& z) { __result.X::X(y, z); return; }
在编译器层面做优化 Optimization at the Compiler Level
>编译器优化操作 Named Return Value(NRV)优化;
>批评1)优化由编译器完成, 实现程度外部不可知; 2)函数变得比较复杂时, 优化难以施行; 3)程序员在某些情况下不希望应用程序优化;
Ex. X xx0(1024); --> xx0.X::X(1024); //单一的constructor操作; Ex. X xx1 = X(1024); X __temp; __temp.X::X(1024), xx1.X::X(__temp); __temp.X::~X(); //调用两个constructor, 对于临时object调用destructor;
Copy Constructor 要还是不要
>default copy constructor被视为trivial, bitwise copy不会导致memory leak和address aliasing, 快速安全;
>memcpy()或memset()都只有在classes不含任何由编译器产生的内部members时才能有效运行.
摘要 copy constructor的应用 会使编译器多少对程序代码做部分转化, 当函数以传值方式传回class object, 而该class有copy constructor(明确定义或者合成出来的), 会导致程序转化--在函数的定义或使用上; 编译器也将copy constructor的调用操作优化, 以一个额外的第一参数取代NRV.
2.4 成员们的初始化队伍 Member Initialization List
>必须使用member initialization list的情况
1)初始化一个reference member; 2)初始化一个const member; 3)调用一个base class的constructor, 而它拥有一组参数时; 4) 调用一个member class的constructor, 而它拥有一组参数时;
>member initialization list提高效率, 避免编译器内部扩张constructor; Ex.
>提高效率的办法 Word::Word() : mName(0) { mCnt = 0; } 扩张--> Word::Word() { mName.string::string(0); mCnt = 0; } //调用了string(0)的constructor;
Notice: >list中的初始化顺序是由class中的members的声明次序决定的, 不是initialization list的排列次序决定的. >Initialization list的操作被放在explicit user code之前;
>编译器会对initialization list处理并可能重新排序, 会安插一些代码到constructor内, 放置于explicit user code之前.
---Section2 End---
相关文章推荐
- Inside the C++ Object Model 深度探索对象模型 5-Construction 6-Runtime 7-Object
- Inside the C++ Object Model 深度探索对象模型 5-Construction 6-Runtime 7-Object
- Inside the C++ Object Model 深度探索对象模型 5-7
- Inside the C++ Object Model 深度探索对象模型 3-DATA 4-Function
- Inside The C++ Object Model (深度探索C++对象模型) 第一讲 关于对象
- 《深度探索C++对象模型(Inside The C++ Object Model )》学习笔记
- 《深度探索C++对象模型(Inside The C++ Object Model )》学习笔记
- C++对象模型《Inside the C++ Object Model》
- Inside The C++ Object Model(七)站在对象模型的尖端
- 《inside the c++ object model》读书笔记 之七 站在对象模型的尖端
- C++对象模型,很多东西来自《Inside the C++ Object Model》一书
- 《深度探索C++对象模型(Inside The C++ Object Model )》学习笔记
- 《深度探索C++对象模型(Inside The C++ Object Model )》学习笔记
- 《深度探索C++对象模型(Inside The C++ Object Model )》学习笔记
- 《深度探索C++对象模型(Inside The C++ Object Model )》学习笔记
- 《深度探索C++对象模型(Inside The C++ Object Model )》学习笔记
- Inside The C++ Object Model 学习笔记 -- 关于对象
- Inside the C++ Object Model 第一讲: 关于对象
- Inside the c++ object model - Copy Constructor Construction
- 读书笔记《Inside the C++ Object Model》:Default Constructor的构造操作