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

C++多态场景下编译器如何识别指针的实际类型?

问题解答

关于编译器是否能获知指针实际类型的问题

首先明确:编译器在编译阶段完全不知道Parent* p的实际指向类型,你所说的动态调用(调用子类重写的foo)也完全不需要编译器修改指针p的类型,这一能力由C的虚函数机制实现,依赖对象自身携带的运行时类型信息,和你传入的只有对象地址的前提完全不冲突。
主流C
编译器的通用实现逻辑如下:

  • 你提到的"重写"本身隐含了Parent::foo是虚函数的前提(C++中只有父类声明为virtual的成员函数才能被子类重写),只要Parent类定义了虚函数,所有Parent类及其派生类的实例内存头部都会隐含一个虚表指针,指向当前类对应的虚函数表,虚函数表中按顺序存储了当前类所有虚函数的实际入口地址。
  • 运行p->foo()时,程序会直接从p指向的内存首地址取出虚表指针,再查询虚表中foo对应的函数地址完成调用。整个过程只需要访问对象自身的内存内容,不需要额外信息,也不需要修改p本身的类型。
    如果Parent::foo没有声明为virtual,就不存在子类重写的语义,只是子类定义了同名函数隐藏了父类实现,此时p->foo()的调用地址在编译期就会被固定为Parent::foo,不管p实际指向什么子类对象,都不会调用子类的实现。

关于两段代码的运行表现对比

你给出的两段代码唯一的区别是Child实例的存储位置:

// 第一段:Child实例在栈上
Child c;
Parent *p = &c;
p->foo();

// 第二段:Child实例在堆上
Parent *p = new Child();
p->foo();

两段代码的运行表现完全一致:

  • 如果foo是虚函数,都会调用Child::foo
  • 如果foo不是虚函数,都会调用Parent::foo
    不需要编译器做任何修改指针类型的操作,二者的多态表现没有任何区别。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 07:15:05