——编译器对非虚方法使用静态联编(编译时匹配),对虚方法使用动态联编(运行时匹配)。数组
静态联编比动态联编效率高。函数
虚函数的工做原理。spa
虚函数。指针
从新定义成员函数(改变函数特征标)。code
从新定义重载的成员函数。对象
效率blog
为使程序可以在运行阶段进行决策,必须采起一些方法来跟踪基类指针或引用指向的对象类型,这增长了额外的处理开销。所以下列状况更适合静态联编:继承
所以静态联编被设置为C++的默认选择。内存
若是要在派生类中从新定义基类的方法,则将它设置为虚方法;不然设置为非虚方法。原型
虚函数的工做原理
编译器处理虚函数的方法是:给每一个对象添加一个隐藏成员。隐藏成员中保存了一个指向·函数地址·数组的指针。这种数组被称为虚函数表(vtbl),表中存储了为类对象进行声明的虚函数的地址。
派生类对象将包含一个指向独立地址表的指针(即新建立一个表)。(增长内存开销)
调用虚函数时,程序将查看存储在对象中的vtbl地址,而后转向相应的函数地址表并在表中查找地址。(影响执行速度)
总之,使用虚函数将在内存和执行速度上有必定的成本;即便非函数的效率比虚函数稍高,却不具有动态联编功能。
构造函数不能是虚函数。
析构函数应当是虚函数,除非类不用作基类。
友元函数不能是虚函数,由于友元不是类成员,而只有成员才能够是虚函数。
若是派生类没有从新定义函数,将使用该函数的基类版本(继承它)。若是派生类位于派生链中,则将使用最新的虚函数版本(指针或引用调用),基类版本被隐藏的状况除外。
从新定义将隐藏基类方法:
class Dwelling { public: virtual void showperks(int a) const; ... }; class Hovel : public Dwelling { public: virtual void showperks() const; ... }
在派生类中从新定义函数(改变了参数特征标),将隐藏同名的基类方法,而不是重载基类方法。
Hovel trump; trump.showperks(); // valid trump.showperks(5); // invalid
若是从新定义继承的方法,应确保与原来的原型彻底相同。若是返回类型为基类引用或指针,则能够修改成指向派生类的引用或指针(返回类型协变:即容许返回类型随类类型的变化而变化)。
若是基类声明被重载了,则应在派生类中从新定义全部的基类版本;若是只定义了一个版本,则其它版本将被隐藏,派生类对象将没法使用它们。
class Dwelling { public: virtual void showperks(int a) const; virtual void showperks(double x) const; virtual void showperks() const; ... }; class Hovel : public Dwelling { virtual void showperks(int a) const; virtual void showperks(double x) const; virtual void showperks() const; ... };
若是不须要修改,则新定义可只调用基类版本:
void Hovel::showperks()const {Dwelling::showperks();}
-----