注意:
1 只需要在基类的函数声明中加上virtual关键字,函数定义时不能加;
2 在派生类中重定义虚函数时,函数特征要相同;
3 当在基类中定义了虚函数时,如果派生类没有重定义该函数,那么将使用基类的虚函数。
4 在派生类中重定义了虚函数的情况下,如果想使用基类的虚函数,可以加类名和域解析符。
5 【应用开发经验】如果要在派生类中重定义基类的函数,则将它设置为虚函数;否则,不要设置为虚函数,有两方面好处:首先效率更高;其次指出不要重新定义该函数。(但是把基类的函数都设置为虚函数,语法上没有任何问题)
内存模型如下
基类:
内存占用8字节
派生类:
也是8字节
加上virtual关键字
基类的内存模型
没加virtual关键字前,基类只有两个成员,大小是8字节,现在的基类有3个成员,大小是16字节,多了一个8字节的vfptr.
vfptr是虚函数指针(virtual function pointer)指向vftable,虚函数表的意思(virtual function table)的意思,在虚函数表中,存放了基类三个虚函数的地址,在虚函数表中,函数的地址用 &类名::函数名 表示。
如果类中没有虚函数,编译的时候,编译器字节把成员函数的地址链接到二进制文件中,如果类中有虚函数,编译的时候,编译器不会把虚函数的地址链接到二进制文件中。
在有虚函数的类中,多了一个隐身的成员:虚函数指针。
程序再运行的过程中,如果创建了对象,除了给对象的成员分配内存,还会创建一个虚函数表,用虚函数指针指向虚函数表,在程序中,如果调用的是普通成员函数,程序的二进制代码中有普通成员函数的地址,字节执行函数就行了,如果调用的是虚函数,要先查找虚函数表,得到函数的地址,再执行函数。
调用普通成员函数的效率比调用虚函数更高,所以说,如果不考虑多态,不要把普通成员函数设置为虚函数。
派生类:
派生类会从基类多继承一个虚函数指针和虚函数表,C++这样设计的目的是为了让基类和派生类保持相同的内存模型,还有,在运行程序的过程中,如果创建了派生类对象,在虚函数表中,会用派生类成员函数的地址取代基类成员函数的地址,
测试下,注释掉其中一个方法,再看下派生类的内存模型
可以看出来,被注释的方法是从基类继承来的,没有被覆盖。