C++ virtual关键词理解

多态

(待续)

虚函数

C++中的虚函数的实现一般是通过虚函数表(C++规范并没有规定具体用哪种方法,但大部分的编译器厂商都选择此方法)。

类的虚函数表是一块连续的内存,每个内存单元中记录一个JMP指令的地址。

注意的是,编译器会为每个有虚函数的类创建一个虚函数表,该虚函数表将被该类的所有对象共享。类的每个虚成员占据虚函数表中的一行。如果类中有N个虚函数,那么其虚函数表将有N*4字节的大小。

虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。简称为V-Table。在这个表中,主要是一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其真实反应实际的函数。这样,在有虚函数的类的实例中分配了指向这个表的指针的内存,所以,当用父类的指针来操作一个子类的时候,这张虚函数表就显得尤为重要了,它就像一个地图一样,指明了实际所应该调用的函数。

编译器应该是保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证取到虚函数表的有最高的性能——如果有多层继承或是多重继承的情况下)。 这意味着可以通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。

(引用: http://www.baike.com/wiki/%E8%99%9A%E5%87%BD%E6%95%B0%E8%A1%A8

纯虚函数

(待续)

例子

(待续)

虚函数的重要规则

  1. 如果虚函数在基类与派生类中出现,仅仅是名字相同,而形式参数不同,或者是返回类型不同,那么即使加上了virtual关键字,也是不会进行滞后联编的。
  2. 只有类的成员函数才能说明为虚函数,因为虚函数仅适合用与有继承关系的类对象,所以普通函数不能说明为虚函数。
  3. 静态成员函数不能是虚函数,因为静态成员函数的特点是不受限制于某个对象。
  4. 内联(inline)函数不能是虚函数,因为内联函数不能在运行中动态确定位置。即使虚函数在类的内部定义,但是在编译的时候系统仍然将它看做是非内联的。
  5. 构造函数不能是虚函数,因为构造的时候,对象还是一片未定型的空间,只有构造完成后,对象才是具体类的实例。
  6. 析构函数可以是虚函数,而且通常声名为虚函数。

菱形继承(虚基类)

(待续)

析构函数

根据上述规则6,具有多态特性的类的析构函数,有必要声明为virtual。如下实例,如果析构函数不用virtual修饰,无法调用子类的析构函数:

输出结果:

如果析构函数不用virtual修饰,则输出结果: