【问题标题】:Protected data in parent class not available in child class?父类中的受保护数据在子类中不可用?
【发布时间】:2010-11-27 17:19:48
【问题描述】:

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

下面的 sn-p 在 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'

我做错了什么?

【问题讨论】:

    标签: c++ protected


    【解决方案1】:

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

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

    【讨论】:

      【解决方案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::queue, std::priority_queue 通过访问其受保护的容器成员 c)

      【讨论】:

      • 嗨 Johannes Schaub - litb 你能告诉我如何访问 std::stack 或 std::queue 中的受保护成员 c 我在访问它时遇到问题它给了我一个错误 C2248:'std: :stack<_ty>::c' : 无法访问在类 'std::stack<_ty>' 中声明的受保护成员 谢谢
      【解决方案3】:

      根据 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;
      }
      

      【讨论】:

      • 嗯。准确地说,这个案例是一个虚拟案例,只是为了演示问题。我实际上想对传入的数据进行一些相当深入的阅读。
      • 在任何情况下,您都只能使用此对象或另一个 B 对象的 A 部分中的受保护数据。如果您有一个 A 实例或一个 C 实例也派生自 A,则 B 对这些 As 没有特殊权限。如果你不能接受这个建议(通过将它复制到这个 B 的基础部分来使这个 A 成为这个 B 的一部分,你可以访问它),那么你可能会遇到一个设计问题,这可能需要更大的图景来回答。
      • @rlbond:睡前又开始编码了。这确实解决了我的问题。谢谢。 :)
      【解决方案4】:

      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;
      }
      

      【讨论】:

      • 我是这么想的,但这不是问题。
      • @jde:实际上这是一个错字。将 B 的构造函数设为 public 会产生同样的错误。
      • @Paul,请修正问题中的任何意外拼写错误,因此进一步的答案不会提出相同的解决方案:)
      猜你喜欢
      • 1970-01-01
      • 2018-12-31
      • 2015-07-18
      • 2016-07-05
      • 2012-03-05
      • 1970-01-01
      • 1970-01-01
      • 2011-10-09
      • 1970-01-01
      相关资源
      最近更新 更多