You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基类指针为何能在虚函数中访问派生类成员?内存布局与this指针解析

关于C++多态中this指针与派生类内存布局的疑问解答

首先先把你给出的代码贴出来方便参考:

class Base { 
public: 
    virtual void test() {}; 
    virtual int get() {return 123;} 
private: 
    int bob = 0; 
}; 
class Derived: public Base{ 
public: 
    virtual void test() { alex++; } 
    virtual int get() { return alex;} 
private: 
    int alex = 0; 
}; 
Base* b = new Derived(); 
b->test();

核心结论:你的理解完全正确!

你提到的「派生类内存布局中包含与基类对象完全一致的子布局」,这正是this指针能同时适配基类指针和派生类成员函数调用的关键原因。

咱们一步步拆解:

  • 当你用Base* b = new Derived()创建对象时,Derived对象的内存布局开头部分,就是一个完整的Base子对象——它的结构和单独创建的Base对象完全相同,包含基类的虚表指针、私有成员bob。在这之后,才是派生类自己的成员alex。
  • 当调用b->test()时,隐式传入的this指针,指向的是Derived对象中Base子对象的起始地址。因为这个子布局和独立Base对象完全一致,所以这个this指针完全可以被当作Base*来正常使用。
  • 但同时,这个Base子对象里的虚表指针,实际指向的是Derived类的虚表(这是多态的核心),所以最终会跳转到Derived::test方法执行。

补充细节:派生类成员函数如何通过基类指针访问自己的成员?

可能你会好奇:Derived::test里访问alex时,this明明是Base*类型,怎么能找到alex?
其实编译器在编译Derived的成员函数时,已经提前计算好了alex相对于Derived对象起始地址的偏移量。当this传入时,虽然它的静态类型是Base*,但实际指向的是Derived对象的Base子对象起始地址——编译器会自动把this指针调整为Derived*类型(加上Base类的大小偏移),然后再去访问alex,这个过程是完全透明的。

注意例外情况

上面的逻辑针对的是普通非虚继承的场景,如果你用了虚继承(比如class Derived: virtual public Base),内存布局会有额外的调整(比如虚基类表),但核心思路还是类似的——编译器会自动处理this指针的偏移,保证成员访问的正确性。

内容的提问来源于stack exchange,提问作者Jerry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:55:11