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

基类指针为何能访问派生类的vptr成员变量?

基类指针为何能访问派生类的vptr?

先看你给出的代码示例:

#include <iostream>

class Base {
public:
    virtual void foo() {
        std::cout << "Base::foo()" << std::endl;
    }
};

class Derived : public Base {
public:
    void foo() override {
        std::cout << "Derived::foo()" << std::endl;
    }
};

int main() {
    Base* basePtr = new Derived();
    basePtr->foo();

    delete basePtr;
    return 0;
}

核心原因可以拆解成这几点:

  • vptr是编译器隐式添加的隐藏成员:你代码里没声明vptr,它是编译器为支持多态,给所有带虚函数的类(包括基类和派生类)自动插入的隐藏成员。对于public继承的派生类对象,其内存布局开头是基类子对象,vptr就存放在这个基类子对象里。当创建Derived对象时,编译器会自动把基类子对象里的vptr指向Derived的vtable,而非Base的。
  • 基类指针指向的是派生类对象的基类子对象起始地址:Base* basePtr = new Derived()执行后,basePtr的地址对应Derived对象中Base子对象的起始位置,这个位置里就存着指向Derived vtable的vptr——编译器生成代码时,知道只要是Base类型的指针(Base是多态类),指向的对象里一定有vptr,所以直接从该地址取vptr,不用管实际对象是Base还是Derived。
  • 非虚成员函数和vptr的访问逻辑完全不同:非虚成员函数是编译期绑定的,编译器会严格按指针的静态类型(Base*)检查成员是否属于Base类,派生类的非虚成员不在Base定义里,所以编译报错。但vptr的访问是编译器处理虚函数调用时自动完成的运行期行为,不是你显式访问某个类成员,因此不受静态类型的编译期检查限制。

简单说:你以为basePtr在“访问Derived的vptr”,其实它只是在访问自己静态类型(Base)要求的那个隐藏vptr成员,而这个成员在派生类对象里被替换成了指向派生类vtable的版本而已。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 16:57:09