设为首页 加入收藏

TOP

1.3 对象的差异(An Object Distinction)(2)
2013-10-07 14:48:54 来源: 作者: 【 】 浏览:67
Tags:1.3 对象 差异 Object Distinction

1.3  对象的差异(An Object Distinction)(2)

你绝对没有办法确定地说出px或rx到底指向何种类型的objects,你只能够说它要么是一个Library_materials object,要么就是后者的一个子类型(subtype)。不过,我们倒是可以确定,dx只能是Library_materials class的一个object。本节稍后,我会讨论为什么这样的行为虽然或许未如你所预期,却是良好的行为。

虽然"对于object的多态操作"要求此object必须可以经由一个pointer或reference来存取,然而C++(www.cppentry.com)中的pointer或reference的处理却不是多态的必要结果。想想下面的情况:

  1. // 没有多态(译注:因为操作对象不是 class object)  
  2. int *pi;  
  3.  
  4. // 没有语言所支持的多态(译注:因为操作对象不是 class object)  
  5. void *pvi;  
  6.  
  7. // ok : class x 视为一个 base class(译注:可以有多态的效果)  
  8. x *px; 

C++(www.cppentry.com),多态只存在于一个个的public class体系中。举个例子,px可能指向某个类型的object,或指向根据public继承关系派生而来的一个子类型(请不要把不良的转换操作考虑在内)。Nonpublic的派生行为以及类型为void*的指针可以说是多态的,但它们并没有被语言明确地支持,也就是说它们必须由程序员通过显式的转换操作来管理(你或许可以说它们并不是多态对象的一线选手)。

C++(www.cppentry.com)以下列方法支持多态:

1.经由一组隐式的转化操作。例如把一个derived class指针转化为一个指向其public base type的指针:

  1. shape *ps = new circle(); 

2.经由virtual function机制:
  1. ps->rotate(); 

3.经由dynamic_cast和typeid运算符:
  1. if ( circle *pc = dynamic_cast< circle>( ps ) ) ... 

多态的主要用途是经由一个共同的接口来影响类型的封装,这个接口通常被定义在一个抽象的base class中。例如Library_materials class就为Book、Video、Puppet等subtype定义了一个接口。这个共享接口是以virtual function机制引发的,它可以在执行期根据object的真正类型解析出到底是哪一个函数实例被调用。经由这样的操作:
  1. Library_material->check_out(); 

我们的代码可以避免由于"借助某一特定library的materials"而导致变动无常。这不只使得"当类型有所增加、修改或删减时,我们的程序代码无须改变",而且也使一个新的Library_materials subtype的供应者不需要重新写出"对继承体系中的所有类型都共通"的行为和操作。

考虑以下这样的代码:

  1. void rotate(  
  2.    X datum,  
  3.    const X *pointer,  
  4.    const X &reference )  
  5. {  
  6.    // 在执行期之前,无法决定到底调用哪一个 rotate() 实例  
  7.    (*pointer).rotate();  
  8.    reference.rotate();  
  9.  
  10.    // 下面这个操作总是调用 X::rotate()  
  11.    datum.rotate();  
  12. }  
  13.  
  14. main() {  
  15.    Z z; // Z 是 X 的一个子类型  
  16.  
  17.    rotate( z, &z, z );  
  18.    return 0;  

经由pointer和reference完成的两个"函数调用操作"会被动态完成!此例中它们都调用Z::rotate()。经由datum完成的"函数调用操作"则可能(或可能不)经由virtual机制。不过,它反正总是调用X::rotate()就是了(这就是所谓的"编译素养"问题:不管经由datum所调用的virtual function采不采用virtual机制,从语意来说,结果都是相同的。4.2节对此有更详细的讨论)。

需要多少内存才能够表现一个class object?一般而言要有:

其nonstatic data members的总和大小。

加上任何由于alignment(译注)的需求而填补(padding)上去的空间(可能存在于members之间,也可能存在于集合体边界)。

译注:alignment就是将数值调整到某数的倍数。在32位计算机上,通常alignment为4 bytes(32位), 以使bus的"运输量"达到最高效率。

加上为了支持virtual而由内部产生的任何额外负担(overhead)。

一个指针 ,不管它指向哪一种数据类型,指针本身所需的内存大小是固定的。举个例子,下面有一个ZooAnimal声明:

  1. class ZooAnimal {  
  2. public:  
  3.    ZooAnimal();  
  4.    virtual ~ZooAnimal();  
  5.  
  6.    // ...  
  7.    virtual void rotate();  
  8.  
  9. protected:  
  10.    int loc;  
  11.    String name;  
  12. };  
  13.  
  14. ZooAnimal za( "Zoey" );  
  15. ZooAnimal *pza = &za; 

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇1.3 对象的差异(An Object Disti.. 下一篇建议21:尽量用new/delete代替mal..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: