高山流水

----- 要黑就黑彻底

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

一. 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的索引来访问的。
    具体的模型参看: 
    1.1 Simple Object Model.JPG

    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本身。
    具体的模型参看: 
    1.2 Member Table Object Model.JPG

    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处。
    具体的模型参看: 
    1.3 C++ Object Model.JPG 

    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 如下:
   

class  X
{
public :
    
virtual   ~ X()  }
    X
&  X( const  X &  rhs)  }

    
virtual   void  foo()  }
}


//  定义一个方法
X foobar()
{
    X xx;
    X 
* px  =   new  X();
    
//  
    xx.foo();
    px
-> foo();

    
//
    delete px;
    
return  xx;
}


//  这个函数可能的转化为:
void  foobar(X &  _result)
{
    _result.X::X();
 
    
//
    px  =   new sizeof (X) );
    
if (px  !=   0 )
        px
-> X::X();

    
//  这里是不使用virtual 机制的foo调用
    
//  注意这里的调用方法,不是用vtbl, 
    
//  这样如果有从class X 继承的类初始化或赋值给X基类时,
    
//  调用foo的方法是X的方法, 是编译时确定的
    foo( & _result);

    
//  是用virtual 机制的foo调用, 它是运行时确定的
 ( * px -> vtbl[ 2 ])(px);

     
//  delete px 
      if (px  !=   0 )
 
{
         (
* px -> vtbl[ 1 ])(px);   //  destructor
         _delete(px);
     }


     
//  
      return  ;



四. 关键词所带来的差异(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 class  Bear :  public  ZooAnimal
 2
 3 public
 4     Bear(); 
 5      ~ Bear(); 
 6
 7      //   
 8      void  rotate(); 
 9      virtual   void  dance(); 
10
11      //   
12 protected
13      enum  Dances   }
14
15     Dances dances_known; 
16      int  cell_block; 
17 }

18
19 ///
20 Bear b(  " Yogi "  ); 
21 Bear  * pb  =   & b; 
22 Bear  & rb  =   * pb; 
23

    具体的内存布局如 
    
    1.5 Layout of Object and Pointer of Derived Class.JPG

    //
    现有   

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. 对象赋值问题
 

 Bear b; 
 ZooAnimal za 
=  b; 

 
//  ZooAnimal::rotate() invoked 
 za.rotate(); 


    这里有两个问题
    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所替代.
   
   


   


   

 

 

 

posted on 2006-04-18 17:31 猩猩 阅读(805) 评论(1)  编辑 收藏 引用 所属分类: C&C++语言

评论

# re: Inside The C++ Object Model 学习笔记 -- 关于对象 2006-04-21 23:31 Harry

我最近也在翻这本书,大家一起看
  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理