C++ 通过类继承的多态实现原理以及虚函数表改写时机

    科技2022-08-20  120

    class Parent{ public: virtual void func() { cout << "Parent" << endl; } }; class Child : public Parent{ public: void func() { cout << "Child" << endl; } }; int main() { Child child; Parent *p4 = &child; p4->func(); //打印Child,父类指针p4竟然运行子类函数 return 0; }

    关于C++多态,我刚开始学的时候有一个疑惑:在Parent *p4 = &child;的情况下:

    p4明明是父类指针,怎么会调用到子类的成员函数呢?


    请明确以下内容:

    p4是指向父类的指针,没有实体,调用成员时,一切都会按照父类的偏移量使用。子类内存有父类那部分内容。编译器将重写的虚函数安排到一个特殊的地址(这个地址就是虚函数表,虚表指针就是指向这个地址)。编译器看到虚函数会覆盖虚函数表对应项。

    根据以上基础内容,虚函数调用过程是: 1.按照父类偏移量偏移到虚表指针。 2.按照父类偏移量从虚表偏移到虚函数,这个虚函数就是被覆盖的虚函数。

    那么为什么非虚函数不会调用到子类函数呢?

    非虚成员是正常分配,是根据类自身偏移的。p4调用非虚成员,实际上就是调用从父类继承过来的那部分内存,所以调用的都是父类成员。

    程序是编译后确定好的,子类(右值)各不相同(但是左右值地址相同、虚函数偏移量相同),看着像虚函数根据右值动态在变,所以被称为动态多态。 不要试图用指针一个个看对象的内存布局,C++标准没有规定布局,不同编译器对象内存布局不一定相同。


    注意:如果子类的继承方式是private,由于父类的虚函数对子类不可见,子类不能override父类的虚函数,那么多态是无效的。

    Processed: 0.013, SQL: 10