C++派生类访问基类实例protected成员报错原因咨询
问题复现
以下代码编译时会在第19行触发报错,提示int B::x is protected within this context, declared protected:
#include <iostream> using namespace std; class B { protected: int x; public: B(int i = 28) { x = i; } virtual B f(B ob) { return x + ob.x + 1; } void show() { cout << x; } }; class D : public B { public: D(int i = -32) : B(i) { } B f(B ob) { return x + ob.x - 1; } //line 19 报错位置 }; int main() { B *p1 = new D, *p2 = new B, *p3 = new B(p1->f(*p2)); p3->show(); return 0; }
报错根因
这个错误来自对C++ protected访问控制规则的认知偏差,规则本身非常明确:
- 基类的
protected成员,派生类仅有权限访问自身实例所继承的那部分基类子对象的对应成员,没有权限访问独立的、纯基类类型对象的protected成员。 - 类的成员函数,可以访问同类型所有对象的
private/protected成员,不受是否是this指向实例的限制。
对应到这段代码:
- 在B类自己的
f成员函数里访问ob.x是完全合法的:ob是B类型,B的成员函数对所有B对象的所有成员都有访问权,所以B类里的这段逻辑不会触发报错。 - 在D类重写的
f函数里,this->x(也就是代码里直接写的x)是合法的:这是D实例从B继承来的、属于自身的基类成员,符合protected访问权限。 - 第19行的
ob.x报错,是因为形参ob是独立的B类型对象,不是D实例内嵌的基类子对象,D的成员函数没有权限访问这个外部B对象的protected成员。
常见误区澄清
- 误区1:派生类里可以访问所有基类对象的protected成员
这个认知是错的。如果把D类f函数的形参从B ob改成D ob,那访问ob.x就不会报错——因为此时ob是D类型的实例,它的x是D自身继承的基类成员,在D的访问权限范围内。 - 误区2:类成员函数只能访问this指向实例的私有/保护成员
这个认知也是错的。比如你在B类里写一个成员函数,接收另一个B类型的对象作为参数,完全可以直接访问这个参数对象的private、protected成员,类的访问控制是按类维度管控的,不是按实例维度管控的。 - 误区3:派生类里拿到基类指针/引用就能访问基类保护成员
只要这个基类指针/引用指向的不是当前派生类实例、也不是同派生类的其他实例,而是独立的基类对象,访问它的protected成员依然会触发编译错误。
内容的提问来源于stack exchange,提问作者Dudu Dudu
相关产品推荐
相关产品推荐

