设为首页 加入收藏

TOP

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

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

当我们写:

  1. pz->rotate(); 

时,pz的类型将在编译时期决定以下两点:

固定的可用接口。也就是说,pz只能够调用ZooAnimal的public接口。

该接口的access level(例如rotate()是ZooAnimal的一个public member)。

在每一个执行点,pz所指的object类型可以决定rotate()所调用的实例。类型信息的封装并不是维护于pz之中,而是维护于link之中,此link存在于"object的vptr"和"vptr所指的virtual table"之间(4.2节对于virtual functions有一个完整的讨论)。

现在,请看以下这种情况:

  1. Bear b;  
  2. ZooAnimal za = b;  // 译注:这会引起切割(sliced)  
  3.  
  4. // 调用 ZooAnimal::rotate()  
  5. za.rotate(); 

为什么rotate()所调用的是ZooAnimal实例而不是Bear实例?此外,如果初始化函数(译注:应用于上述assignment操作发生时)将一个object内容完整拷贝到另一个object去,为什么za的vptr不指向Bear的virtual table?

第二个问题的答案是,编译器在(1)初始化及(2)指定(assignment)操作(将一个class object指定给另一个class object)之间做出了仲裁。编译器必须确保如果某个object含有一个或一个以上的vptrs,那些vptrs的内容不会被base class object初始化或改变。

至于第一个问题的答案是:za并不是(而且也绝不会是)一个Bear,它是(并且只能是)一个ZooAnimal。多态所造成的"一个以上的类型"的潜在力量,并不能够实际发挥在"直接存取objects"这件事情上。有一个似是而非的观念:OO程序设计并不支持对object的直接处理。举个例子,下面这一组定义:

  1. {  
  2.    ZooAnimal za;  
  3.    ZooAnimal *pza;  
  4.  
  5.    Bear b;  
  6.    Panda *pp = new Panda;  
  7.  
  8.    pza = &b;  

其可能的内存布局如图1.6所示。
 
(点击查看大图)图1.6  依序定义下的内存布局

将za或b的地址,或pp所含的内容(也是个地址),指定给pza,显然不是问题。一个pointer或一个reference之所以支持多态,是因为它们并不引发内存中任何"与类型有关的内存委托操作(type-dependent commitment)";会受到改变的,只有它们所指向的内存的"大小和内容解释方式"而已。

然而,任何人如果企图改变object za的大小,会违反其定义中受契约保护的"资源需求量"。如果把整个Bear object指定给za,则会溢出它所配置得到的内存。执行结果当然也就不对了。

当一个base class object被直接初始化为(或是被指定为)一个derived class object时,derived object就会被切割(sliced)以塞入较小的base type内存中,derived type将没有留下任何蛛丝马迹。多态于是不再呈现,而一个严格的编译器可以在编译时期解析一个"通过此object而触发的virtual function调用操作",因而回避virtual机制。如果virtual function被定义为inline,则更有效率上的大收获。

总而言之,多态是一种威力强大的设计机制,允许你继一个抽象的public接口之后,封装相关的类型。我所举的Library_materials体系就是一例。需要付出的代价就是额外的间接性--不论是在"内存的获得"或是在"类型的决断"上。C++(www.cppentry.com)通过class的pointers和references来支持多态,这种程序设计风格就称为"面向对象"。

C++(www.cppentry.com)也支持具体的ADT程序风格,如今被称为object-based(OB)。例如String class,一种非多态的数据类型。String class可以展示封装的非多态形式;它提供一个public 接口和一个private实现品,包括数据和算法,但是不支持类型的扩充。一个OB设计可能比一个对等的OO设计速度更快而且空间更紧凑。速度快是因为所有的函数调用操作都在编译时期解析完成,对象建构起来时不需要设置virtual机制;空间紧凑则是因为每一个class object不需要负担传统上为了支持virtual机制而需要的额外负荷。不过,OB设计比较没有弹性。

OO和OB设计策略都有它们的拥护者和批评者。你可以在[BOOCH93]、[CARROLL93]和[LEA93]找到一些有趣的正反两方面论点的讨论。这些论文所讨论的,是C++(www.cppentry.com) Booch Components library、Bell Laboratories' Standard C++(www.cppentry.com) Components library,以及GNU g++library的设计决策。在弹性(OO)和效率(OB)之间常常存在着取与舍。一个人能够有效选择其一之前,必须先清楚了解两者的行为和应用领域的需求。

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇1.3 对象的差异(An Object Disti.. 下一篇1.1 C++对象模式(The C++ Objec..

评论

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