关于vtable实现动态分派时基类如何找到正确重写方法的困惑
缺失的箭头在哪里?
我在读Bjarne Stroustrup的《A Tour of C++》第二版第四章时,始终搞不懂一个问题:指向派生类对象的基类指针,调用虚函数时是怎么找到正确的成员方法的?
书中给出了从Container类派生的示例,Container的定义如下:
class Container { public: virtual double& operator[](int) = 0; // 纯虚函数 virtual int size() const = 0; // const成员函数 virtual ~Container() {} // 析构函数 };
书中还配了一张展示vtable(虚函数表)结构的图示。
同时,书中提供了一个操作Container对象的函数:
void use(Container& c) { const int sz = c.size(); for (int i=0; i!=sz; ++i) std::cout << c[i] << '\n'; }
我清楚vtables属于编译器的实现细节,并不在C++标准的规定范围内,但还是想搞懂这个底层机制。
一开始我就疑惑,为什么作为函数参数的基类指针/引用可以接受派生类实例作为实参,于是查了不少其他资料。有些教程的图示里包含了vtable指针,但没讲明白Base*是怎么识别出自己指向的是Derived对象的。
我的核心困惑在于:我原本以为Base*得持有指向派生类所有成员方法的指针,调用时通过某种“转换”(我觉得这种转换效率肯定不高)才能找到正确的方法,但这显然太复杂了。比如有一张图示里,Base*指向了对象,但没有画出指向派生类vtable的箭头——它到底是怎么知道自己指向的是派生类对象的?是不是这张图示漏掉了这个关键的箭头?
我还看过一些关于动态分派的问题,但都是针对Java的,不是C++的。我理解Class B和Class C各自只有一份类蓝图,每次用new创建对象时,都会基于这份蓝图生成实例,实例存储在堆/自由存储区里,但还是没搞懂虚函数调用的底层逻辑。
内容的提问来源于stack exchange,提问作者heretoinfinity
相关产品推荐
相关产品推荐

