私有继承场景下,非指针/引用调用时虚函数的工作机制解惑
为什么非指针/引用调用时虚函数依然生效?
这个问题其实戳中了很多人对虚函数绑定的误区——很多人以为只有用指针或者引用调用虚函数才会触发动态绑定,但实际上核心点不在调用方式,而在于调用时的this指针的实际指向。咱们结合你的代码一步步拆解:
首先先看你提供的代码:
#include <iostream> class Base { public: virtual void f() { std::cout << "Base::f()" << std::endl; } void g() { f(); } }; class Derived : private Base { public: void f() { std::cout << "Derived::f()" << std::endl; } void h() { g(); } }; int main(){ Derived d; d.h(); // 输出Derived::f(),但若移除Base::f()的virtual关键字则输出Base::f() }
核心原因:隐式的this->f()触发了动态绑定
你看Base::g()里直接写的f(),其实是C++的语法糖,完整写法是this->f()。这里的this有两个关键属性:
- 静态类型是
Base*:也就是编译器在编译Base::g()时,认为this是指向Base对象的指针; - 动态类型是
Derived*:但实际运行时,this指向的是Derived对象里的Base子对象(因为Derived继承了Base,不管继承权限是私有还是公有,对象内存中都包含基类子对象)。
而虚函数的动态绑定逻辑,就是看调用时的动态类型——编译器会通过this指向的对象的虚表,找到对应类型的函数实现,所以这里就会调用Derived::f()。
为什么去掉virtual就变成调用Base::f()?
如果Base::f()没有virtual关键字,那它就是普通成员函数,调用时会触发静态绑定:编译器只会根据当前函数(Base::g())所在的类,直接把调用绑定到Base::f(),完全不管this实际指向的是什么对象,所以输出就变成了Base::f()。
补充:私有继承不影响虚函数机制
可能你会疑惑,Derived是私有继承Base,为什么还能触发基类里的虚函数调用?其实私有继承只是限制了外部代码对基类成员的访问权限,完全不影响对象内部的虚表结构和动态绑定逻辑——Derived对象的虚表里,f()的条目早就被替换成了自己的实现,只要是通过this调用虚函数,就会走动态绑定的流程。
内容的提问来源于stack exchange,提问作者user2696565
相关产品推荐
相关产品推荐

