Inside The C++ Object Model 学习笔记 -- 关于对象

时间:2022-11-26 20:37:37

一. C/C++ 语言中的方法和数据

    1. C语言的数据和方法     语言中数据和处理(函数)是分开的,语言本身不支持数据和函数的关联性。这种方法我们称之为:程序性的;它是由"分布在各个以功能为导向的函数中"d的算法所驱动,它们处理的是共同的数据。

     2. C++语言数据和方法
     C++中是通过ADT(Abstract Data Type, ADT)来实现的。 C++可以在不同层次上进行抽象,造成的复杂度可能也不一样。
     书中从简单到复杂四个层次的抽象: 简单类、继承、一个参数的Template、两个参数的模板。


二.C++加上封装后的布局成本(Layout Costs for Adding Encapsulation)

    1. C++中的对象的布局
    a. data member:  直接的包涵在每一个class object(注意: 类对象,不是类)之中,这和C struct的情况是一样的
    b. member function: 它不出现在class object 之中.
       non-inline member: 它会产生一个行数的实体. 如果是非static的funciton, 每个function会加上一个this指针作为function的第一个参数.
       inline member: 会在每一个使用者身上产生一个函数的实体。这一般是为了提高效率。
   
    2. C++布局和存取上的额外开销
    a. virtual function 机制: 用以支持一个有效的"执行期绑定(runtime binding)" 
    b. virtual base class


三. C++对象模型(The C++ Object Model)

    1. 简单对象模型(A Simple Object Model)
    这种模型中,每个object是一系列的slots, 每个slot指向一个member. 每个member按其申明的次序各占用一个slot. 这里的member包括data member 和 function member. 每个member是通过slot的索引来访问的。
    具体的模型参看: 
    Inside The C++ Object Model 学习笔记 -- 关于对象

    2. 表格驱动模型(A Table-driven Object Model)
    这种模型中把class object的members分组放在一个data member table 和一个function member table中,class object内含两个指向table的指针. member function table 是一系列的slots, 每个slot指向一个function member. data member table 则是直接的包涵有data本身。
    具体的模型参看: 
    Inside The C++ Object Model 学习笔记 -- 关于对象

    3. C++对象模型(The C++ Object Model)
    C++的对象模型如下:
    a. nostatic data members 被直接的配置在每一个class object之内。
    b. static data member 、static 和 nonstatic function members全部被放在所有的class object 之外。
    c. virtual functions 则是以下列步骤支持的:
        i. 每一个class 产生一堆指向virtual functions的指针,放在表格之中,我们称这个表格为:virtual table(vtbl).
 ii. 每个得class object 被添加了一个指针,指向相关的virtual table,我们把class object的这个指针称之为vptr(virtual pointer);这个vptr的设定和重置是由类的constructor、destructor 和 copy assignment 运算符自动完成的;每个类的type_info object也是经由virtual table指出的,通常是放在表格的第一个slot处。
    具体的模型参看: 
    Inside The C++ Object Model 学习笔记 -- 关于对象 

    d. 加上继承(Adding Inheritance)
    在 A Simple Object Model 中,每一个基类可以被derived class object的一个slot指出,该slot内含base class subobject的地址。
    在虚拟继承的情况下,base class 不管在继承链中被派生多少次,永远只有一个实体(subobject). 书中以iostream继承体系说明。

    C++中的base class subobject的data members直接放置于derived class object中。那么它的function members是怎么处理的呢?(我没有理解这块)
    对于virtual base class, C++ 2.0 是在class object中添加一个关联 virtual base class object的指针。

    e. 对象模型对程序的影响
    我觉得书上的这段代码非常好的体现了不同模型对程序的影响
    预定义 class X 如下:
   

Inside The C++ Object Model 学习笔记 -- 关于对象class  X
Inside The C++ Object Model 学习笔记 -- 关于对象Inside The C++ Object Model 学习笔记 -- 关于对象
{
Inside The C++ Object Model 学习笔记 -- 关于对象
public :
Inside The C++ Object Model 学习笔记 -- 关于对象Inside The C++ Object Model 学习笔记 -- 关于对象    
virtual   ~ X() Inside The C++ Object Model 学习笔记 -- 关于对象 }
Inside The C++ Object Model 学习笔记 -- 关于对象Inside The C++ Object Model 学习笔记 -- 关于对象    X
&  X( const  X &  rhs) Inside The C++ Object Model 学习笔记 -- 关于对象 }
Inside The C++ Object Model 学习笔记 -- 关于对象
Inside The C++ Object Model 学习笔记 -- 关于对象Inside The C++ Object Model 学习笔记 -- 关于对象    
virtual   void  foo() Inside The C++ Object Model 学习笔记 -- 关于对象 }
Inside The C++ Object Model 学习笔记 -- 关于对象}

Inside The C++ Object Model 学习笔记 -- 关于对象
Inside The C++ Object Model 学习笔记 -- 关于对象
//  定义一个方法
Inside The C++ Object Model 学习笔记 -- 关于对象
X foobar()
Inside The C++ Object Model 学习笔记 -- 关于对象Inside The C++ Object Model 学习笔记 -- 关于对象
{
Inside The C++ Object Model 学习笔记 -- 关于对象    X xx;
Inside The C++ Object Model 学习笔记 -- 关于对象    X 
* px  =   new  X();
Inside The C++ Object Model 学习笔记 -- 关于对象    
//  
Inside The C++ Object Model 学习笔记 -- 关于对象
    xx.foo();
Inside The C++ Object Model 学习笔记 -- 关于对象    px
-> foo();
Inside The C++ Object Model 学习笔记 -- 关于对象
Inside The C++ Object Model 学习笔记 -- 关于对象    
//
Inside The C++ Object Model 学习笔记 -- 关于对象
    delete px;
Inside The C++ Object Model 学习笔记 -- 关于对象    
return  xx;
Inside The C++ Object Model 学习笔记 -- 关于对象}

Inside The C++ Object Model 学习笔记 -- 关于对象
Inside The C++ Object Model 学习笔记 -- 关于对象
//  这个函数可能的转化为:
Inside The C++ Object Model 学习笔记 -- 关于对象
void  foobar(X &  _result)
Inside The C++ Object Model 学习笔记 -- 关于对象Inside The C++ Object Model 学习笔记 -- 关于对象
{
Inside The C++ Object Model 学习笔记 -- 关于对象    _result.X::X();
Inside The C++ Object Model 学习笔记 -- 关于对象 
Inside The C++ Object Model 学习笔记 -- 关于对象    
//
Inside The C++ Object Model 学习笔记 -- 关于对象
    px  =   new sizeof (X) );
Inside The C++ Object Model 学习笔记 -- 关于对象    
if (px  !=   0 )
Inside The C++ Object Model 学习笔记 -- 关于对象        px
-> X::X();
Inside The C++ Object Model 学习笔记 -- 关于对象
Inside The C++ Object Model 学习笔记 -- 关于对象    
//  这里是不使用virtual 机制的foo调用
Inside The C++ Object Model 学习笔记 -- 关于对象    
//  注意这里的调用方法,不是用vtbl, 
Inside The C++ Object Model 学习笔记 -- 关于对象    
//  这样如果有从class X 继承的类初始化或赋值给X基类时,
Inside The C++ Object Model 学习笔记 -- 关于对象    
//  调用foo的方法是X的方法, 是编译时确定的
Inside The C++ Object Model 学习笔记 -- 关于对象
    foo( & _result);
Inside The C++ Object Model 学习笔记 -- 关于对象
Inside The C++ Object Model 学习笔记 -- 关于对象    
//  是用virtual 机制的foo调用, 它是运行时确定的
Inside The C++ Object Model 学习笔记 -- 关于对象Inside The C++ Object Model 学习笔记 -- 关于对象 ( * px -> vtbl[ 2 ])(px);
Inside The C++ Object Model 学习笔记 -- 关于对象
Inside The C++ Object Model 学习笔记 -- 关于对象     
//  delete px 
Inside The C++ Object Model 学习笔记 -- 关于对象
      if (px  !=   0 )
Inside The C++ Object Model 学习笔记 -- 关于对象Inside The C++ Object Model 学习笔记 -- 关于对象 
{
Inside The C++ Object Model 学习笔记 -- 关于对象         (
* px -> vtbl[ 1 ])(px);   //  destructor
Inside The C++ Object Model 学习笔记 -- 关于对象
         _delete(px);
Inside The C++ Object Model 学习笔记 -- 关于对象     }

Inside The C++ Object Model 学习笔记 -- 关于对象
Inside The C++ Object Model 学习笔记 -- 关于对象     
//  
Inside The C++ Object Model 学习笔记 -- 关于对象
      return  ;

Inside The C++ Object Model 学习笔记 -- 关于对象

Inside The C++ Object Model 学习笔记 -- 关于对象


四. 关键词所带来的差异(A Keyword Distinction)

    讨论了class 和 struct 的差异和选择

五. 对象的差异( A Object Distinction)

    1. C++程序设计模型支持三种programming paradigms.
    a. 程序模型(procedural model) 就是像 C 一样进行编程
    b. 抽象数据类型模型(abstract data type model, ADT) 用对象进行编程
    c. 面向对象模型(object-oriented model)
    模型中有一些彼此相关的类型,通过一个抽象的base class被封装起来(也就是:接口)。类型之间的操作是通过接口进行的。

    纯粹的以一种paradigm写程序是好的.(哈哈,好像这不太可能,我还做不到)

   二. 面向对象模型(object-oriented model)
    a . C++中多态支持性的支持是通过: pointer 和 reference来实现的.
    多态通过下面三种方法来支持:
        i. 经由一组隐含的转化操作:   shape *ps = new circle();
        ii. 经由virtual function 机制  ps->rotate();
        iii. 经由 dynamic_cast和typeid来支持:
             if(circle *pc = dynamic_cast<circle*>(ps)) ...
   多态内存需求
       i. 其 nonstatic data members 的总和大小
       ii. 任何字节对齐的额外填充(padding)
       iii. 支持virtual 而产生的额外负担
    
    b. 指针的类型
    "指向不同类型的各指针"的差异,不在于其指针的表示法不同,也不在于其内容的不同, 而是其寻址出来的object的类型不同。也就是说"指针类型"会教导编译器如何解释某个特定地址中的内存内容及其大小.

    c.  加上多态之后(Adding Polymorphism)
    以如下为例:    

 1 Inside The C++ Object Model 学习笔记 -- 关于对象class  Bear :  public  ZooAnimal
 2 Inside The C++ Object Model 学习笔记 -- 关于对象Inside The C++ Object Model 学习笔记 -- 关于对象
 3 Inside The C++ Object Model 学习笔记 -- 关于对象public
 4 Inside The C++ Object Model 学习笔记 -- 关于对象    Bear(); 
 5 Inside The C++ Object Model 学习笔记 -- 关于对象     ~ Bear(); 
 6 Inside The C++ Object Model 学习笔记 -- 关于对象
 7 Inside The C++ Object Model 学习笔记 -- 关于对象     //  Inside The C++ Object Model 学习笔记 -- 关于对象 
 8 Inside The C++ Object Model 学习笔记 -- 关于对象     void  rotate(); 
 9 Inside The C++ Object Model 学习笔记 -- 关于对象     virtual   void  dance(); 
10 Inside The C++ Object Model 学习笔记 -- 关于对象
11 Inside The C++ Object Model 学习笔记 -- 关于对象     //  Inside The C++ Object Model 学习笔记 -- 关于对象 
12 Inside The C++ Object Model 学习笔记 -- 关于对象protected
13 Inside The C++ Object Model 学习笔记 -- 关于对象Inside The C++ Object Model 学习笔记 -- 关于对象     enum  Dances  Inside The C++ Object Model 学习笔记 -- 关于对象 }
14 Inside The C++ Object Model 学习笔记 -- 关于对象
15 Inside The C++ Object Model 学习笔记 -- 关于对象    Dances dances_known; 
16 Inside The C++ Object Model 学习笔记 -- 关于对象     int  cell_block; 
17 Inside The C++ Object Model 学习笔记 -- 关于对象}

18 Inside The C++ Object Model 学习笔记 -- 关于对象
19 Inside The C++ Object Model 学习笔记 -- 关于对象Inside The C++ Object Model 学习笔记 -- 关于对象 ///
20 Inside The C++ Object Model 学习笔记 -- 关于对象Bear b(  " Yogi "  ); 
21 Inside The C++ Object Model 学习笔记 -- 关于对象Bear  * pb  =   & b; 
22 Inside The C++ Object Model 学习笔记 -- 关于对象Bear  & rb  =   * pb; 
23 Inside The C++ Object Model 学习笔记 -- 关于对象

    具体的内存布局如 
    
    Inside The C++ Object Model 学习笔记 -- 关于对象

    //
    现有   

1  Bear b;
2  ZooAnimal  * pz  =   & b;
3  Bear  * pb  =   & b;
4 

以上每个都指向Bear object的第一个byte,其间的差别是,pb所涵盖的地址包含整个的Bear object, 而pz所涵盖的地址只包含Bear object中的 ZooAnimal subobject部分。你只能用pz来处理Bear中的virtual functions, 而不能直接的处理Bear中的其他任何members.
    注意pz的类型将在编译时确定以下两点:
     i. pz固定的可用接口
     ii. pz的接口的access level;因为子类的access level可能是不同于基类的,编译时会检测是否可以转换。

    e. 对象赋值问题
 

Inside The C++ Object Model 学习笔记 -- 关于对象 Bear b; 
Inside The C++ Object Model 学习笔记 -- 关于对象 ZooAnimal za 
=  b; 
Inside The C++ Object Model 学习笔记 -- 关于对象
Inside The C++ Object Model 学习笔记 -- 关于对象 
//  ZooAnimal::rotate() invoked 
Inside The C++ Object Model 学习笔记 -- 关于对象
 za.rotate(); 
Inside The C++ Object Model 学习笔记 -- 关于对象
Inside The C++ Object Model 学习笔记 -- 关于对象


    这里有两个问题
    i. za为什么调用的是ZoomAnimal::rotate的实体而不是 Bear的实体?
   答:za并不是一个Bear, 它只是一个ZoomAnimal, 多态的这种特性不能用在直接存取的objects上。所以  za.rotate()调用只能是 ZooAnimal::rotate()

    ii. 如果初始化函数将一个object的内容完全拷贝到另一个object中去,为什么za的vpt不是指向Bear的virtual table呢?
    答:编译器在初始化或赋值操作时,如果某个object含有一个或多个vptrs, 那么这些vptrs的内容不会被原对象初始化或改变.
 例如上例的 ZooAnimal za = b, 这里的vptr并不会被 b 的vptr所替代.