系列文章目录
提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:虚成员函数和动态联编
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
提示:这里可以添加本文要记录的大概内容:
例如:虚成员函数和动态联编
提示:以下是本篇文章正文内容,下面案例可供参考
一、pandas是什么?
示例: 静态联编和动态联编001
二、使用步骤
1.引入库
来回顾一下使用引用或指针调用方法的过程。请看下面的代码:
//derived-class objectBrassPlus ophelia;Brass * bpibp = &ophelia;bp->ViewAcct();
//base-class pointer
//Brass pointer to BrassPlus object//which version?
正如前面介绍的,如果在基类中没有将ViewAcct()声明为虚的,则bp->ViewAcct()将根据指针类型(Brass*)调用 Brass::ViewAcct()。指针类型在编译时已知,因此编译器在编译时,可以将 ViewAcct()关联到 Brass::ViewAcct()。总之,编译器对非虚方法使用静态联编。
然而,如果在基类中将 ViewAcct()声明为虚的,则 bp->ViewAcct()根据对象类型(BrassPlus)调用BrassPlus::ViewAcct()。在这个例子中,对象类型为BrassPlus,但通常(如程序清单13.10所示)只有在运行程序时才能确定对象的类型。所以编译器生成的代码将在程序执行时,根据对象类型将ViewAcct()关联到 Brass::ViewAcct()或 BrassPlus::ViewAcct()。总之,编译器对虚方法使用动态联编。在大多数情况下,动态联编很好,因为它让程序能够选择为特定类型设计的方法。因此,您可能会问:为什么有两种类型的联编?
既然动态联编如此之好,为什么不将它设置成默认的?
动态联编是如何工作的?
下面来看看这些问题的答案,
1.为什么有两种类型的联编以及为什么默认为静态联编
如果动态联编让您能够重新定义类方法,而静态联编在这方面很差,为何不摒弃静态联编呢?原因有两个–效率和概念模型。
首先来看效率。为使程序能够在运行阶段进行决策,必须采取一些方法来跟踪基类指针或引用指向的对象类型,这增加了额外的处理开销(稍后将介绍一种动态联编方法)。例如,如果类不会用作基类,则不
需要动态联编。同样,如果派生类(如 RatedPlayer)不重新定义基类的任何方法,也不需要使用动态联编。在这些情况下,使用静态联编更合理,效率也更高。由于静态联编的效率更高,因此被设置为C++的默认选择。Strousstrup说,C++的指导原则之一是,不要为不使用的特性付出代价(内存或者处理时间)。仅当程序设计确实需要虚函数时,才使用它们。
接下来看概念模型。在设计类时,可能包含一些不在派生类重新定义的成员函数。例如,Brass::Balance(函数返回账户结余,不应该重新定义。不将该函数设置为虚函数,有两方面的好处:首先效率更高;其次,指出不要重新定义该函数。这表明,仅将那些预期将被重新定义的方法声明为虚的。
提示:如果要在派生类中重新定义基类的方法,则将它设置为虚方法;否则,设置为非虚方法。
当然,设计类时,方法属于哪种情况有时并不那么明显。与现实世界中的很多方面一样,类设计并不
是一个线性过程。
2.虚函数的工作原理
C++规定了虚函数的行为,但将实现方法留给了编译器作者。不需要知道实现方法就可以使用虚函数但了解虚函数的工作原理有助于更好地理解概念,因此,这里对其进行介绍。通常,编译器处理虚函数的方法是:给每个对象添加一个隐藏成员。隐藏成员中保存了一个指向函数地址数组的指针。这种数组称为虚函数表(virtual function table,vtbl)。虚函数表中存储了为类对象进行声明的虚函数的地址。例如,基类对象包含一个指针,该指针指向基类中所有虚函数的地址表。派生类对象将包含一个指向独立地址表的指针。如果派生类提供了虚函数的新定义,该虚函数表将保存新函数的地址:如果派生类没有重新定义虚函数,该 vtbl将保存函数原始版本的地址。如果派生类定义了新的虚函数,则该函数的地址也将被添加到vtb1中(参见图13.5)。注意,无论类中包含的虚函数是1个还是 10个,都只需要在对象中添加1个地址成员,只是表的大小不同而已。
调用虚函数时,程序将查看存储在对象中的 vtbl地址,然后转向相应的函数地址表。如果使用类声明中定义的第一个虚函数,则程序将使用数组中的第一个函数地址,并执行具有该地址的函数。如果使用类声明中的第三个虚函数,程序将使用地址为数组中第三个元素的函数。总之,使用虚函数时,在内存和执行速度方面有一定的成本,包括:
每个对象都将增大,增大量为存储地址的空间;
对于每个类,编译器都创建一个虚函数地址表(数组);
对于每个函数调用,都需要执行一项额外的操作,即到表中查找地址。
虽然非虚函数的效率比虚函数稍高,但不具备动态联编功能。
总结
提示:这里对文章进行总结:
例如:暂无