11

我很困惑:我认为受保护的数据可以被 C++ 中给定类的孩子读/写。

下面的代码片段无法在 MS 编译器中编译

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'

我究竟做错了什么?

4

4 回答 4

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;
}
于 2009-09-12T07:05:21.903 回答
2

C++ 标准说关于受保护的非静态成员11.5/1

当派生类的友元或成员函数引用基类的受保护非静态成员函数或受保护非静态数据成员时,除了前面第 11 节中描述的那些之外,还应用访问检查。除非形成指向成员的指针(5.3 .1),访问必须通过派生类本身(或从该类派生的任何类)的指针、引用或对象(5.2.5)。如果访问要形成指向成员的指针,则嵌套名称说明符应命名派生类(或从该类派生的任何类)。

除了修复其他人前面提到的东西(构造函数B是私有的)之外,我认为 rlbond 的方式会做得很好。但是,标准的上述段落的直接后果是使用成员指针可以进行​​以下操作,这可以说是类型系统中的一个漏洞,当然

class B : public A {
public:
  B(A &a){
    int A::*dataptr = &B::data;
    data = a.*dataptr;
  }
};

当然,不建议这样做,但表明您可以访问它,如果您真的需要(我已经看到这种方式被用于打印出std::stack, std::queuestd::priority_queue通过访问其受保护的容器成员c

于 2009-09-12T10:48:52.583 回答
1

您只是不应该在构造函数中复制A对象。目的是将's 成员B的初始化留给它自己的构造函数:A

struct A { 
  A( const A& a ): data( a.data ) {}
  protected: int data; 
};

struct B : public A {
  B( const A& a ): A( a ) {}
};
于 2009-09-12T11:18:18.503 回答
0

B 的构造函数是私有的。如果你没有指定任何东西,在一个类中,默认修饰符是私有的(对于结构来说它是公共的)。所以在这个例子中,问题是你不能构造 B。当你将 public 添加到构造函数 B 时,会出现另一个问题:

在这种情况下,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;
}
于 2009-09-12T06:59:52.260 回答