1. 宏比函数更有效率:
void print(const Point3d *pd){
printf("(%g,%g,%g)",pd.x,pd.y,pd.z);
}
可以替换为更高效的宏:
#define Point3d_print(pd) \
printf("(%g,%g,%g)",pd.x,pd.y,pd.z);
注意:宏中的\表示把下一行拼接在当前行后面。
2. 相比于C语言,C++在布局(加上封装后的布局,通常与布局成本联系)以及存取时间上的主要额外负担来自于virtual引起的,包括:
virtual function机制:用以支持有效率的“执行期绑定(runtime binding)”,也称为“动态绑定”,实现多态(Polymorphism), 多态性是将接口与实现进行分离。
virtual base class:用以实现"多次出现在继承体系中的base class,有且只有一个单一而被共享的实例",即在派生类在继承多个基类时,具有相同【根基类】的基类全是虚继承,防止该【根基类】的实例在继承体系中多次出现。如代码:
class base{..}
class other{...}
class childA:public base{..}
class C:vistual public base, vistual public childA, public other
{
..
}
- 派生类在构造函数进行构造的时候,会先调用基类的构造函数完成基类部分的构造后,才看是自身的构造。因此,在多继承中,位于最底端的派生类,在构造的时候很有可能会多次调用【根基类】,此时,虚继承很好的解决了这个问题,即【根基类】相当于只被构造一次。
- 这里的 virtual是共享的意思。
3. 三种OO模型:
(1)简单对象模型(ASimple Object Model)
在这个简单模型中,每个object都是一系列的slot(插槽),每个slot指向一个成员,每一个数据成员和成员函数都有自己的slot.在这个模型下,members不放在object里,只有指向member的指针才放在object中,这么做可以避免“member有不同类型,因而需要不同存储空间”所招致的问题。Object中的member是以slot的索引值来寻址的,本例子中_x的索引是6,_point_count的索引是7.这样,一个 class object的大小很容易计算出来,即指针大小*class中声明的member数。
虽然这个模型没用实际应用,但索引或slot个数的观念,被应用到C++的“指向成员的指针”的观念中。
(2)表格驱动对象模型(A Table-drivern Object Model)
为了对所有的classes的所有objects都有一致的表达,另一种对象模型是把所有与members相关的信息抽出来,放在data member table和member function table中, class objects本身则内含指向这2个表的指针。member function table是一些列的slots,每一个slot指出一个member function; data member table则直接持有data本身
虽然这个模型也未被采用到C++编译器中,但member function table这个观念却成为支持virtual function的一个有力方案。
(3) C++对象模型
Stroustrup设计的最初C++模型是从简单对象模型派生而来,并对内存和存取时间做了优化。在此模型中,非静态数据成员被放置于每个class object之内,静态数据成员被存放在个别class object 之外。静态和非静态成员函数也被放在个别class object之外。Virtual function以两个步骤支持之:
1. 每一个class产生一堆指向virtual function的指针,放在表格中,这个表格被称为virtual table (vtbl);
2. 每一个class object被安插一个指针,指向相关的virtual table,该指针被称为vptr。 vptr的设定和重置都由每一个class的构造,析构和copy assignment运算符自动完成。每一个class关联的type_info object(用以支持runtime type identification, RTTI)也经由virtual table被指出来,通常放在表格的第一个slot。
一种class只产生一个 virtual table(vtbl),该类的所有对象都会被(编译器或系统)安插一个指向该table的指针vptr。
这个模型的主要优点是空间和存取效率,缺点是一旦class object的非静态数据成员有所修改(增,删,改),那么应用程序代码需要重新编译。关于此点,前面表格驱动中的双表格模型可以提供较大弹性,因为它多了一层间接性,因此也付出了空间和执行效率的代价。
4. struct与class
C:struct
C++ : class
在cfront(第一个C++实现品,有Lippman完成)之中,上述两个关键词在语义分析器(parser)中是以共享的“AGGR”替换的。C++中继续保留struct,完全是为了兼容C。但在C++中,除了struct默认成员为public而class默认为private外,两者没有任何区别,可以交叉继承,如;
struct s{..};
class c{..};
class b: public s{...};
struct s2: public c{...};
此外,struct在下面场景及其适用:“当要传递一个复杂的class object的部分或者全部” 到某个C函数去时,struct声明可以将数据封装起来,并保证拥有与C兼容的空间布局。
在C++中,struct定义的成员默认是public,但可以像class一样,分public,protected和private,可同时包含数据成员和成员函数。而在 C里,结构体都只有数据成员,而没有函数成员。
5. 在OO Paradigm之中,继承体系中的某个未知实例,他的类型虽然有所界定,但却有无穷可能,原则上,被指定的object的真实的类型在每一个特定执行点之前,是无法解析的。在C++中,只有通过pointers指针和reference引用的操作才能完成。相反,在ADT paradigm中,程序员处理的是一个拥有固定而单一类型的实例,编译时就能确定好。
C++支持三种programming paradigm:
程序模型procedural model
抽象数据类型模型 abstract data type model,ADT
面向对象模型object-oriented model
参考文献:
[1] Stanley B.lippman. inside the C++ Object Model(深度探索C++对象模式)[M].电子工业出版社,2012.