一、什么是联编
- 联编:将源代码中的函数调用解释为执行特定的函数代码块被称为函数名的联编(binding)。
- 静态联编: 在编译过程中进行联编被称为静态联编,又称为早期联编。
- 动态联编:编译器必须生成能够在程序运行时选择正确的虚方法的代码,这被称为动态联编,又称为晚期联编。
二、为什么有两种类型的联编以及为什么默认为静态联编?
- 效率
动态联编效率低。因为要跟踪基类指针或引用指向的对象类型,增加了额外开销。
如果类不需要作为基类,则不需要动态联编。
如果派生类不需要重新定义类的任何方法,不需要动态联编。
- 概念
在设计类时,可能包含一些不在派生类重新定义的成员函数。不将这些函数设置为虚函数,有两方面的好处:首先效率更高;其次指出不需要重新定义该函数。
三、虚函数工作原理
- 虚函数表:虚函数表是一个存储了类中虚函数地址的数组,虚函数表是在编译阶段生成的,每个类有一个虚函数表。
通常编译器处理虚函数的方法是:
- 给每个对象添加一个隐藏成员,这个隐藏成员指向虚函数表,被称为虚表指针,虚表指针是在运行时(创建对象时)生成的。
- 基类对象的虚表指针指向基类的虚函数表,派生类对象的虚表指针,指向派生类的虚表。
- 基类的虚表和派生类的虚表是两个独立的虚表。构建派生类的虚表时,如果派生类提供了虚函数的新定义,则虚函数表将保存新函数的地址;如果派生类没有重新定义虚函数,则保存的是基类中的该虚函数的地址;如果派生类定义了新的虚函数,则该函数的地址被添加到虚表中。
四、虚函数注意事项
- 构造函数不能为虚函数。因为:1)创建派生类时要调用派生类的构造函数,而不是基类的构造函数,这和虚函数实现多态的目标不符。2)不同于继承基值,派生类不会继承基类的构造函数,而是调用派生类的构造函数需要先调用基类的构造函数。