在介绍多态之前,我们应该知道什么是虚函数?什么是虚函数重写?
虚函数:
类的
成员函数
前面加virtual关键字,则这个成员函数称为虚函数。
注:除静态成员函数
虚函数重写:
当在子类的定义了一个与父类
完全相同的
虚函数时,则称子类的这个函数
重写(也称覆盖)了父类的这个虚函数。
多态
定义:
当使用
基类的指针或引用调用重写的虚函数时,当指向父类调用的就是父类的虚函数,当指向子类调用的就是子类的虚函数。
条件:
1.虚函数重写 2.父类的指针和引用
eg:
class Base { public : virtual void func1() { cout<<"Base::func1" <<endl; } virtual void func2() { cout<<"Base::func2" <<endl; } public: int a ; }; class Derive :public Base { public : virtual void func1() { cout<<"Derive::func1" <<endl; } virtual void func3() { cout<<"Derive::func3" <<endl; } virtual void func4() { cout<<"Derive::func4" <<endl; } public: int b ; };
这是一种运行期多态,即父类指针唯有在程序运行时才能知道所指的真正类型是什么。这种运行期决议,是通过虚函数表来实现的。
多态对象模型
使用指针访问虚表
eg:
class Base { public : virtual void func1() { cout<<"Base::func1" <<endl; } virtual void func2() { cout<<"Base::func2" <<endl; } public: int a ; }; typedef void(*V_FUNC)(); void PrintVTable(int** vtable) { cout<<"===================================="<<endl; printf("虚函数表:%p\n", vtable); for (size_t i = 0; vtable[i] != 0; ++i) { printf("vfunc[%d]:%p->", i, vtable[i]); V_FUNC f = (V_FUNC)vtable[i]; f(); } cout<<"===================================="<<endl; } void Test() { Base b; PrintVTable((int**)(*((int**)&b))); }
分析:
单继承对象模型
写一个类继承Base
eg:
class Derive :public Base { public : virtual void func1() { cout<<"Derive::func1" <<endl; } virtual void func3() { cout<<"Derive::func3" <<endl; } virtual void func4() { cout<<"Derive::func4" <<endl; } public: int _b ; };
分析:
在C++对象模型中,对于一般继承(这个一般是相对于虚拟继承而言),若子类重写(overwrite)了父类的虚函数,则子类虚函数将覆盖虚表中对应的父类虚函数(注意子类与父类拥有各自的一个虚函数表);若子类并无overwrite父类虚函数,而是声明了自己新的虚函数,则该虚函数地址将扩充到虚函数表最后(在vs中无法通过监视看到扩充的结果,不过我们通过取地址的方法可以做到,子类新的虚函数确实在父类子物体的虚函数表末端)。
多继承对象模型(非菱形继承)
eg:
class Base1 { public : virtual void func1() { cout<<"Base1::func1" <<endl; } virtual void func2() { cout<<"Base1::func2" <<endl; } private : int b1 ; }; class Base2 { public : virtual void func1() { cout<<"Base2::func1" <<endl; } virtual void func2() { cout<<"Base2::func2" <<endl; } private : int b2 ; }; class Derive : public Base1, public Base2 { public : virtual void func1() { cout<<"Derive::func1" <<endl; } virtual void func3() { cout<<"Derive::func3" <<endl; } private : int d1 ; }; typedef void(*V_FUNC)(); void PrintVTable(int** vtable) { cout<<"===================================="<<endl; printf("虚函数表:%p\n", vtable); for (size_t i = 0; vtable[i] != 0; ++i) { printf("vfunc[%d]:%p->", i, vtable[i]); V_FUNC f = (V_FUNC)vtable[i]; f(); } cout<<"===================================="<<endl; } void Test() { Derive d; PrintVTable((int**)(*((int**)&d))); PrintVTable((int**)(*(int**)((char*)&d+sizeof(Base1)))); }
分析:
单继承中(一般继承),子类会扩展父类的虚函数表。在多继承中,子类的虚函数被放在声明的第一个基类的虚函数表中。