【C++】透视C++多态:从虚函数表到底层内存布局的完全拆解
. 多态原理下面这段代码中Buy()函数如果传入的是Person调用的就是Person::BuyTicket()传Student调用的是Student::BuyTicket。这样就构成了多态而多态的调用实现是依靠运行时去指向对象的虚表中查调用的函数地址。代码语言javascriptAI代码解释class Person { public: Person(const char* name 张三) :_name(name) {} virtual void BuyTicket() { cout _name 购票,需要排队,每人 100 endl; } protected: string _name; }; class Student : public Person { public: Student(const char* name) :_name(name) {} virtual void BuyTicket() { cout _name 购票,需要排队,每人 50 endl; } private: string _name; }; void Buy(Person* p) { p-BuyTicket(); } int main() { Person p(张三); Buy(p); Student st(张同学); Buy(st); return 0; }通过监视窗口我们可以发现Person指向对象p时p-BuyTicket()在p的虚表中找到虚函数是Person::TicketStudent指向对象st时st-BugTicket在st的虚表中找到虚函数是Student::Ticket通过查找不同的虚函数就实现了不同的对象调用会有不同的行为也就是多态我们再明确一下实现多态的两个条件存在虚函数、需要对象指针或引用调用虚函数通过反汇编窗口可以发现构成了多态之后函数的调用是在运行了程序过程中去对象中取的而不是编译时就决定的如果不是多态函数调用会在编译时就决定好多态调用运行时决议运行时才确定函数的地址普通函数编译时决议编译时确认调用函数的地址2. 动态绑定与静态绑定静态绑定前期绑定编译时就决定了调用哪个函数根据变量或表达式的静态类型决定也就形成了静态多态如函数重载动态绑定后期绑定在程序运行时根据拿到的具体类型来确定函数的具体行为也就形成动态动态如下面这个和上面那个p-BuyTicket()对比就知道动态绑定和静态绑定的区别3. 单继承和多继承中的虚函数表3.1. 单继承中的虚函数表代码语言javascriptAI代码解释class Base { public: virtual void Func1() { cout Base::Func1() endl; } virtual void Func2() { cout Base::Func2() endl; } private: int _b 1; }; 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; } private: int _d 2; }; int main() { Base b; Derive d; return 0; }通过调试时我们发现似乎有些问题理论上派生类d应该会有三个虚函数继承基类的两个新增加的两个但是我们发现虚表中只有两个指针我们看不到Func3()和Func4()这里是编译器隐藏了这两个函数可以认为是VS的一个Bug。