C++中存在protected非const函数时,const成员函数为何不可访问?
为何protected的非const成员会导致const成员无法被调用?
先看你给出的示例代码:
struct Fooo { void func() const {} protected: void func() {} }; // ... Fooo fooo; fooo.func();
编译器报错说func不可访问,原因是选中的protected版本无法被外部调用,但你原本以为会忽略protected版本,直接调用public的const版本。这背后是C++的重载决议顺序规则在起作用。
核心逻辑:重载决议先于访问控制
C++编译器处理函数调用时,会严格遵循以下顺序:
- 收集所有匹配的重载候选:对于非const对象
fooo,两个func()都是合法的候选——const成员函数可以被非const对象调用,非const成员函数同样匹配。 - 选择最佳匹配的重载:在两个候选中,非const版本的
func()匹配度更高(因为调用者是非const对象,编译器优先选择不需要const转换的重载)。 - 检查选中函数的访问权限:此时发现选中的非const
func()是protected,外部无法访问,因此报错。
简单说:编译器不会因为某个重载不可访问就跳过它去选次优的匹配,而是先选最匹配的,再检查能不能访问。
结合你的派生类场景理解
看你给出的Base类示例:
class Base { int a; public: const auto& getA() const { return a; } protected: auto& getA() { return a; } }; class PublicAccess : public Base { public: Base::getA; // 将Base的getA重载集引入public域 };
这里PublicAccess中Base::getA;的作用是把基类的getA重载集整体引入public访问域。此时外部调用PublicAccess对象的getA()时:
- 如果是const对象,会匹配const版本;
- 如果是非const对象,会匹配非const版本,且这个版本现在是public的,所以可以正常调用。
而KeepProtected类没有调整访问权限,所以非const版本仍然是protected,外部非const对象调用getA()时,同样会先选中非const版本,然后因为访问权限报错。
为什么要这么设计?
这种规则是为了保证重载行为的一致性:如果允许跳过不可访问的重载去选次优匹配,会导致同一组重载在不同访问权限下的调用结果不一致,增加代码的不确定性。同时也能避免开发者意外"绕过"访问控制——比如原本protected的函数是不想让外部调用的,若因为访问权限就跳过它,可能会违背设计意图。
内容的提问来源于stack exchange,提问作者Newline
相关产品推荐
相关产品推荐

