C++中通过基类暴露派生类私有虚成员的原理探究
C++虚函数私有覆盖后仍可通过基类调用的原因
问题描述
发现一段C++代码,派生类B中将覆盖的虚函数设为私有,但通过基类A的引用却能调用到该私有函数,代码如下:
#include <iostream> class A { public: virtual void print() const { std::cout << "hello A" << std::endl;} }; class B: public A { private: void print() const override { std::cout << "hello B" << std::endl;} }; int main() { const A &a = B(); a.print(); // 输出"hello B",超出预期 const B &b = B(); b.print(); // 编译报错,符合预期 }
为何a.print()能够正常执行并输出"hello B"?难道C++在运行时会忽略private/public访问限定符吗?原本以为派生类中print()是私有的,a.print()不会生效。
解答
核心原因在于C++的访问权限检查发生在编译阶段,而动态绑定是运行阶段的行为,二者完全独立:
- 当通过基类
A的引用a调用print()时,编译器在编译阶段只会检查静态类型(即A类)中print()的访问权限——A::print()是public的,因此编译直接通过,不会去管派生类中该函数的权限。 - 运行阶段,动态绑定机制会根据对象的实际类型(
B)找到对应的B::print()实现并执行,此时不会再做任何访问权限检查,因为权限验证已经在编译阶段完成了。
而直接用B类的引用b调用print()时,编译器检查的是**静态类型B**中print()的权限,发现它是private,因此直接触发编译错误,程序根本到不了运行阶段。
简单来说:访问权限看的是调用时的静态类型(引用/指针的类型),动态绑定看的是运行时的实际对象类型,二者互不干扰,这是C++标准规定的行为。
内容的提问来源于stack exchange,提问作者Foma Roje
相关产品推荐
相关产品推荐

