类继承-虚函数(2)

关于指针和引用的兼容性:

通常,C++不允许将一种类型的地址赋给另一终类型的指针,也不允许将一种类型的引用指向另一种类型。但是,在类继承中,我们看到了可以将派生了Derived对象的地址赋给基类指针Based*,或者将基类的引用Based&指向派生类Derived对象,只是允许的,为什么呢?

首先,公有继承确定了派生类对象和基类对象是一种is-a的关系(即Derived对象都是一个Based对象)。将派生类引用或者指针转换成基类引用或者指针被称为向上强制转换,公有继承不需要进行显式类型转换,派生类拥有基类的所有数据成员和方法,对基类的任何操都是适用于派生类。向上强制转换是可以传递的,即Based的引用或者指针可以指向Based对象、Derived对象、DerivedPlus对象。
相反的过程:将基类的引用或者指针转换成派生类的引用或者指针,称为向下强制转换,是不允许的,因为Is-a关系是不可逆的。派生类的新增数据成员和方法都不适用于基类。

动态联编和静态联编:

在编写的代码中,通常会存在重载函数和普通函数,编译器通过函数名和函数参数确定使用哪个函数,在编译过程中就确定源代码中的函数调用解释为特定的代码块,称为静态联编。
然而使用了虚函数,使用哪个函数是不能在编译时确定的,因为编译器不确定用户将使用哪种类型的对象,所以编译器必须生成能够在程序运行时选择正确的虚函数方法的代码,即动态联编。

虚函数工作原理:

编译器处理虚函数的方法是:给每个对象添加一个隐藏成员,隐藏成员中保存一个指向函数地址数组的指针(vptr),存放虚函数的地址数组即虚函数表(virtual function table,vtbl)。当然,vtbl是该类所有对象共有的(毕竟该类所有的函数地址都是一样的,没必要每个对象都保存一张表,完全可以公用),但是vptr必须是每个对象都有。

基类对对象包含一个指针,该指针指向基类中所有虚函数的地址表。派生类对象将包含一个指向独立地址表的指针:如果派生类提供了虚函数的新定义,该虚函数表将保存新函数的地址;如果没有重新定义虚函数,将保存函数的原始版本的地址;如果派生类定义了新的虚函数,则将该函数的地址加到派生类的虚函数表中。

调用虚函数时,程序将查看存储在对象中的vtbl地址(难道是公有成员?)然后转向相应的函数地址表。通过vtbl就达到了跟踪基类指针或引用指向的对象类型。

小结:使用虚函数时,在内存和执行效率方面有一定成本。非虚函数效率比虚函数高,但是不具备动态联编功能。

  • 每个对象都将增大,增大的量为存储地址的空间
  • 对于每一个类,编译器都将创建一个虚函数地址表(数组)
  • 对于每个虚函数的调用,都将执行一项额外的操作,即到vtbl中查找函数地址。

使用虚函数的注意事项

  • 1构造函数:
    构造函数不能是虚函数,和一般的成员函数不一样。派生类对象创建时调用的是派生类的构造函数,而不是基类的构造函数。派生类不继承基类的构造函数,因此将基类的构造函数声明为虚函数是没有意义的。
    (还有一个说法有待考证:虚函数表是调用构造函数是创建的,虚函数表存放的是该类的虚函数的地址,如果构造函数是虚函数,那么虚函数表中就会有构造函数的地址,当我们调用构造函数时,事先根据vptr找到vtbl中虚构造函数的地址,执行构造函数,这和虚函数表是在执行构造函数是创建的相矛盾了)(啊啊啊啊!!!虚拟函数表是在编译期就建立了,各个虚拟函数这时被组织成了一个虚拟函数的入口地址的数组.而对象的隐藏成员–虚拟函数表指针是在运行期–也就是构造函数被调用时进行初始化的,这是实现多态的关键。)

  • 析构函数
    为保证派生类能够正确顺序的析构,析构函数应当是虚函数。

  • 友元
    友元不能是虚函数,因为友元不是类成员,而只有类成员可以是虚函数。但是友元函数可以使用虚成员函数。

  • 重新定义将隐藏方法
    重新定义继承的方法并不是重载,这将隐藏基类中的同名方法,而不论参数列表是否相同。
    因此派生类中重新定义了基类的同名方法,应保持和原来基类的函数原型完全一致,但如果函数的返回值是基类的指针或者引用,则可以修改成指向派生类的指针或者引用(例外),允许返回类型随类类型的变化而变化。
    如果基类的方法被重载了,最好在派生类中重新定义这些基类方法,否者未重新定义的方法将被隐藏。

纯虚函数

纯虚函数的格式:(声明的结尾处为=0)

virtual  void test()=0;

纯虚函数提供未实现的方法,包含纯虚函数的类称为抽象基类(Abstruct Base Class,简称ABC)。不能创建抽象基类的对象(已经很抽象了,还想有对象)。
可以使用抽象基类的指针或者引用管理其派生类对象。
纯虚方法用于定义派生类的通用接口。

猜你喜欢

转载自blog.csdn.net/qq_29689907/article/details/84575109
今日推荐