C++中的虚成员函数和动态联编是什么?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。
虚成员函数:
虚函数允许派生类取代基类所提供的实现。编译器确保当对象为派生类时,取代者(译注:即派生类的实现)总是被调用,即使对象是使用基类指针访问而不是派生类的指针。这样就允许基类的算法被派生类取代,即使用户不知道派生类的细节。
派生类可以完全地取代基类成员函数(覆盖(override)),也可以部分地取代基类成员函数(增大(augment))。如果愿意的话,后者由派生类成员函数调用基类成员函数来完成。
在构造函数访问顺序中,一般来说是先访问父类的构造函数再访问子类的构造函数,析构函数则是先访问子类的析构函数,再访问父类的析构函数。
动态联编:
编译程序在编译阶段并不能确切知道将要调用的函数,只有在程序运行时才能确定将要调用的函数,为此要确切知道该调用的函数,要求联编工作要在程序运行时进行,这种在程序运行时进行联编工作被称为动态联编。动态联编又称动态关联。
编译器对非虚方法使用静态联编(编译时匹配),对虚方法使用动态联编(运行时匹配)。
静态联编比动态联编效率高。
虚函数的工作原理。
虚函数。
重新定义成员函数(改变函数特征标)。
重新定义重载的成员函数。
效率
为使程序能够在运行阶段进行决策,必须采取一些方法来跟踪基类指针或引用指向的对象类型,这增加了额外的处理开销。因此下列情况更适合静态联编:
因此静态联编被设置为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(); // validtrump.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();}
看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注亿速云行业资讯频道,感谢您对亿速云的支持。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。