为何无法通过父类指针访问子类独有的成员方法?
问题解答:基类指针无法调用派生类独有虚函数的原因
先看你提供的示例代码:
#include <iostream> using namespace std; class base { public: base() {} ~base() {} virtual void funcBase() { cout << "funcBase in class base" << endl; } }; class derived : public base { public: derived() {} ~derived() {} virtual void funcBase() { cout << "funcBase in class derived" << endl; } virtual void funcDerived() {} // I add virtual keyword to make sure funcDerived method is added in vtable of class }; int main() { base* obj = new derived(); obj->funcBase(); // will print funcBase in class derived -> it's normal obj->funcDerived(); // error: 'class base' has no member named 'funcDerived' return 0; }
核心原因:编译期检查优先于运行期多态
你混淆了C++的编译期静态检查和运行期多态机制:
- 编译阶段,编译器只认指针的静态类型(也就是
base*),它会检查base类中是否存在funcDerived方法。因为base里没有这个成员,所以直接编译报错,根本不会进入运行阶段。 - 你说的vptr、vtable是运行期多态的实现细节,只有当调用的函数是基类中声明的虚函数时,运行期才会通过vptr找到实际对象的vtable,执行对应派生类的函数。但前提是这个函数在编译期能通过静态类型的检查。
关于vtable和vptr的补充说明
- 每个包含虚函数的类都会生成一个vtable,里面存放该类所有虚函数的地址。
- 派生类的vtable包含两部分内容:
- 继承自基类的虚函数(如果派生类重写了,就放派生类的版本;否则保留基类的版本)
- 派生类自己新增的虚函数
- 但vtable是运行期才会用到的东西,编译期编译器不关心实际对象的vtable里有什么,它只根据指针的静态类型做语法检查。
解决方法
如果一定要通过base*调用funcDerived,有两种可行方式:
- 把
funcDerived加入基类的接口,声明为纯虚函数或普通虚函数:
class base { public: // ... virtual void funcDerived() = 0; // 纯虚函数,基类无需实现,强制派生类重写 };
- 将
base*安全转换为derived*(推荐用dynamic_cast,需要开启RTTI):
if (derived* d_obj = dynamic_cast<derived*>(obj)) { d_obj->funcDerived(); }
dynamic_cast会在运行时检查对象的实际类型,只有当obj确实指向derived对象时,转换才会成功,避免非法访问。
内容的提问来源于stack exchange,提问作者Ngoc Hai
相关产品推荐
相关产品推荐

