我收到编译错误,我对此感到有些困惑。这是在VS2003上。
错误C2248:'A :: y':无法访问在类'A'
中声明的受保护成员class A
{
public:
A() : x(0), y(0) {}
protected:
int x;
int y;
};
class B : public A
{
public:
B() : A(), z(0) {}
B(const A& item) : A(), z(1) { x = item.y;}
private:
int z;
};
问题在于x = item.y;
将访问权限指定为受保护。为什么B类的构造函数不能访问A :: y?
答案 0 :(得分:5)
正因为如此:
class base_class
{
protected:
virtual void foo() { std::cout << "base::foo()" << std::endl; }
};
class A : public base_class
{
protected:
virtual void foo() { std::cout << "A::foo()" << std::endl; }
};
class B : public base_class
{
protected:
virtual void foo() { std::cout << "B::foo()" << std::endl; }
public:
void bar(base_class *b) { b->foo(); }
};
如果这是合法的,你可以这样做:
A a;
B b;
b.bar(&a);
你要从B调用A的protected
成员,这是不允许的。
答案 1 :(得分:3)
其他答案解释了阻止B
对象访问示例中A
的受保护部分的原因,即使B
'是一个'A
。当然,解决此问题的最简单方法是使A you want access to
部分公开或具有可公开访问的访问方法。
但是,您可能认为这是不合适的(或者您可能无法控制A
的定义)。以下是一些建议,让您可以解决问题,增加破坏A
访问控制的顺序。请注意,所有这些变通方法都假设class A
是可复制的。
在第一种情况下,您只需使用A
的复制构造函数为B
对象的该部分设置初始状态,然后再修复它:
class B1 : public A
{
public:
B1() : A(), z(0) {}
B1(const A& item) : A(item), z(1) {
// fix up the A sub-object that was copy constructed
// not quite the way we wanted
x = y;
y = 0;
}
private:
int z;
};
我发现令人难以置信的混淆并且可能非常容易出错(假设我们希望A
对象中的B
子对象与传递给A
对象的B
对象不同构造函数 - 一个不寻常的情况,但这是问题中给出的)。然而,它可以做的事实为后面的更具颠覆性的例子提供了一些理由......
下一个示例创建一个临时A
对象,该对象与我们想要访问的B
对象完全相同。然后,我们可以使用临时class B2 : public A
{
public:
B2() : A(), z(0) {}
B2(const A& item) : A(), z(1) {
// create a special-use B2 object that can get to the
// parts of the A object we want access to
B2 tmp( item, internal_use_only);
x = tmp.y; // OK since tmp is of type B
}
private:
int z;
// create a type that only B2 can use as a
// 'marker' to call a special constructor
// whose only purpose in life is to create
// a B object with an exact copy of another
// A sub-object in it
enum internal_use {
internal_use_only
};
B2( const A& item, internal_use marker) : A(item), z(0) {};
};
对象来获取受保护的项目:
A
我觉得这个解决方案比第一个解决方案有点混乱,但它仍然令人困惑(在我看来)。拥有B对象的混蛋版本只是为了到达我们想要的A对象的部分是奇怪的。
我们可以通过为A
对象创建一个特殊代理来提供我们想要的访问权限。请注意,这是“最具颠覆性”的解决方法,因为它是任何类都可以访问A
的受保护部分,即使它们本身不是B
的子类。对于A
类,获取B
个对象的受保护部分有一定的合法性,因为A
是一个class B
,而且我们已经看到有一些解决方法让我们获得仅使用class B
已拥有的权限的访问权限,因此我认为这是class B3 : public A
{
public:
B3() : A(), z(0) {}
B3(const A& item) : A(), z(1) {
// a special proxy for A objects that lets us
// get to the parts of A we're interested in
A_proxy tmp( item);
x = tmp.get_y();
}
private:
int z;
class A_proxy : public A
{
public:
A_proxy( const A& other) : A(other) {};
int get_x() {return x;};
int get_y() {return y;};
};
};
案例中这些变通办法的更清晰版本。
{{1}}
答案 2 :(得分:1)
IBM的文档最好地概括了它:
受保护的非静态基类 会员可以访问会员和 任何类的朋友都来自 通过使用其中一个基类 以下内容:
- 指向直接或间接派生类的指针
- 对直接或间接派生类的引用
- 直接或间接派生类的对象
因此,以上面的例子为基础:
B::B(const A& item) : A(), z(1) {
// NOT OK because `item` is not a reference to the derived class B
//int i = item.y;
// OK because `item` reinterpreted as a reference to the derived class B
// Do not do this (bad!) -- for illustrative purposes only
int i = reinterpret_cast< const B& >(item).y;
// OK because it is equivalent to `this->x = i`,
// where `this` is a pointer to the derived class B
x = i;
}