1. 取一个对象的地址(指针或引用),并将其作为基类的地址来处理,这被称为向上类型转换(upcasting)。
2. 创建虚函数时,在函数声明的前面加上关键字virtual,定义时并不需要。如果一个函数在基类中声明为virtual,那么在所有的派生类中它都是virtual的。在派生类中virtual函数的重定义通常称为重写——overriding。
3. 在基类中声明一个类为virtual,调用所有匹配基类声明行为的派生类函数都将使用虚机制。无需在派生类声明前使用关键字virtual。
4. 捆绑:把函数体与函数调用相联系成为捆绑binding。捆绑在程序运行之前由编译器和连接器完成时,称为早捆绑(early binding)。晚捆绑(late binding)意味着捆绑根据对象的类型,发生在运行时,晚捆绑又称为动态捆绑或运行时捆绑(dynamic/runtime binding)。
5. 晚捆绑的实现:编译器对每个包含虚函数的类创建一个表(VTABLE),放置虚函数的地址。在该函数中,有一个指针vpointer(VPTR),指向这个对象的VTABLE。当通过基类指针作虚函数调用时(也就是多态调用),编译器静态的插入能取得这个VPTR 并在VTABLE表中查找函数地址的代码,这样就能调用正确的函数并引起晚捆绑的发生。
6. 虚函数的类的程度:不带虚函数的普通类,对象的长度恰好就是所期望的。而带有单个虚函数的对象的长度是普通变量的长度加上一个v o i d指针的长度。它反映出,如果有一个或多个虚函数,编译器在这个结构中插入一个指针( V P T R)。类中有几个虚函数长度之间没有区别,这是因为V P T R指向一个存放地址的表,只需要一个指针,因为所有虚函数地址都包含在这个表中。
7. 在基类中加入最少一个纯虚函数(pure virtual function),可以使基类成为抽象(abstract)类,纯虚函数使用关键字virtual,并在其后面加上=0。
8. 纯虚函数防止产生VTABLE,但这并不意味着我们不希望对其他函数产生函数体。我们常常希望调用一个函数的基类版本,即便它是虚拟的。把公共代码放在尽可能靠近我们的类层次根的地方,这是很好的想法。这不仅节省了代码空间,而且能允许使改变的传播变得容易
9. 如果使用对象而不是使用地址或引用进行向上映射,这个对象被“切片”,直到所剩下来的是适合于目的的子对象。
评论