我很困惑:我认为受保护的数据是C ++中给定类的子节点可读/写的。
以下代码段无法在MS Compiler中编译
class A
{
protected:
int data;
};
class B : public A
{
public:
B(A &a)
{
data = a.data;
}
};
int main()
{
A a;
B b = a;
return 0;
}
错误讯息:
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
demoFail.cpp
demoFail.cpp(12) : error C2248: 'A::data' : cannot access protected member declared in class 'A'
demoFail.cpp(4) : see declaration of 'A::data'
demoFail.cpp(2) : see declaration of 'A'
我做错了什么?
答案 0 :(得分:10)
根据TC ++ PL,第404页:
派生类只能为其自身类型的对象访问基类'受保护成员....这可以防止在一个派生类破坏属于其他派生类的数据时可能发生的细微错误。
当然,这是一个简单的方法来解决这个问题:
class A
{
protected:
int data;
};
class B : public A
{
public:
B(const A &a)
: A(a)
{
}
};
int main()
{
A a;
B b = a;
return 0;
}
答案 1 :(得分:2)
C ++标准说明了11.5/1
当派生类的朋友或成员函数引用受保护的非静态成员函数或受保护的基类的非静态数据成员时,除了前面第11章中描述的那些之外,还应用访问检查。除非形成指向member(5.3.1),访问必须通过指向,引用或派生类本身的对象(或从该类派生的任何类)(5.2.5)。如果访问要形成指向成员的指针,则嵌套名称说明符应命名派生类(或从该类派生的任何类)。
除了修复其他人之前提到的事情(B
的构造函数是私有的)之外,我认为rlbond的方式可以做得很好。但是,标准的上一段的直接后果是,使用成员指针可能会出现以下情况:当然,这可能是类型系统中的一个洞,
class B : public A {
public:
B(A &a){
int A::*dataptr = &B::data;
data = a.*dataptr;
}
};
当然,不推荐使用此代码,但如果您确实需要,则表示您可以访问它(我已经看到这种方式用于打印{{1 }},std::stack
,std::queue
访问受保护的容器成员std::priority_queue
)
答案 2 :(得分:1)
您只是不应复制A
构造函数中的B
对象。目的是将A
成员的初始化保留给它自己的构造函数:
struct A {
A( const A& a ): data( a.data ) {}
protected: int data;
};
struct B : public A {
B( const A& a ): A( a ) {}
};
答案 3 :(得分:0)
B的构造函数是私有的。如果未在类中指定任何内容,则默认修饰符为private(对于结构,它是公共的)。所以在这个例子中问题是你不能构造B.当你向构造函数B添加public时,会出现anoter问题:
B有权在这种情况下修改它派生的A部分而不是其他A部分。
您可以执行以下操作:
class A
{
public:
A()
: data(0)
{
}
A(A &a)
{
data = a.data;
}
protected:
int data;
};
class B : public A
{
public:
B(A &a)
: A(a)
{
}
};
int main()
{
A a;
B b = a;
return 0;
}