C++ 当受到保护时,保护太多

C++ 当受到保护时,保护太多,c++,inheritance,protected,C++,Inheritance,Protected,这是关于“protected”的,解释为:“当一个类继承另一个类时,派生类的成员可以访问从基类继承的受保护成员。”但是,请看以下代码: class Base { public: Base( int m ) : member(m){} protected: int member; }; class Derived : public Base { // one of several subclasses public: Derived( int m ) : Base(m), value

这是关于“protected”的,解释为:“当一个类继承另一个类时,派生类的成员可以访问从基类继承的受保护成员。”但是,请看以下代码:

class Base {
public:
  Base( int m ) : member(m){}
protected:
  int member;
};

class Derived : public Base { // one of several subclasses
public:
  Derived( int m ) : Base(m), value(10) {}
  int diff( Base x ){
    return value - x.member;
  }
private:
  int value;
};
派生访问“x.member”,它在基类中受保护,对吗?但是编译器会标记一个错误,“Base::member受保护”。在仔细考虑了一分钟后,我不得不同意编译器的观点

问题来了:我该如何在信息隐藏损失最小的情况下实现这一点

  • 显然,将“成员”公开汇编,但这违背了初衷
  • 在Base中使用“friend”机制让子类访问“member”(以及所有其他私有和受保护的内容)甚至更糟糕(除了将超类愚蠢地绑定到自己的子类——维护噩梦)
  • 在这个简单的示例中,可以接受公共int getMember(){return member;}。但是,如果成员的类型是X*,那么最好使用publicconstX*getMember(){…}

  • 我遗漏了什么吗?

    您可以保留受保护的属性,添加您提到的getter函数。对于受保护的指针属性,getter将确保返回
    int
    (或大型对象的const ref),并且您可以在函数模板中执行不同操作,该模板采用派生参数和基参数(getter为您提供计算值)

    保护数据属性允许直接访问派生类中的受保护属性。您尝试的是访问另一个对象的私有属性。这部分代码:

    int diff( Base x ){
        return value - x.member;
      }
    
    这相当于在
    main
    中写入:

    Base x; 
    cout << x.member << endl;
    
    由于NULL PTR,请使用
    -std=c++11
    编译程序,或将其更改为
    NULL


    您将
    diff
    作为函数模板,这样您就不必为每个派生类重载它,并且您可以让派生类处理存储和对它的访问,例如
    PointerDerived

    您可以使用静态保护访问器:

    class Base {
    public:
      Base( int m ) : member(m){}
    private:
      int member;
    protected:
      static int GetMember(const Base &b)
      { return b.member; }
    };
    
    class Derived : public Base { // one of several subclasses
    public:
      Derived( int m ) : Base(m), value(10) {}
      int diff( Base &x ){ //beware of your slicing!
        return value - GetMember(x);
      }
    private:
      int value;
    };
    

    现在让我添加我的想法,为什么C++访问控制这样工作……/P> < C++中的访问控制不是信息隐藏。它是关于封装的。也就是说,简单地说,您过滤掉了对任何成员的访问,如果使用不当,这些成员可能会破坏类

    在理想的班级里

    • 公共成员不能用于断开对象
    • 私人成员知道他们在做什么
    正如您所看到的,在我的计划中,受保护的成员几乎没有位置:

    • 受保护的成员用于实现继承接口(如果有)
    而受保护的成员变量的位置就更少了


    因此,将变量设为私有,并编写一个受保护的访问器。访问器必须是静态的,才能从派生对象使用。

    只需定义
    int diff(派生x)
    ,还是不定义?阅读第1点和第3点时,可以得出结论,保护成员感知是可以读取,但不能更改。因此,get方法可以很好地实现这一点。此外,还可以使用一个公共常量引用或指向const to member的const指针,该引用或指针在Base的构造函数列表中初始化。您的第3点和“您能做的最好的…const X*”取决于您想要什么:get方法无论如何都会返回值。因此,无法使用
    X*get()
    更改类型为X*的成员的值。只有它所指向的。如何制作一个函数
    int diff(派生的d,基b)
    ,并将此函数作为两个类的
    朋友?@mb84 diff-type-Base,以便使其对所有可能的子类型都有用。(可能Base*会让意图更清楚,但我不是在追求多态性。)-我最初的情况是成员的类型为char*,我不喜欢返回这个指针,即使是const char*@rozina OK,如果没有太多地方需要这种访问的话。这段代码中的一些代码回答了一个没有被问到的问题。我真的不确定这对OP也有帮助,更不用说其他试图找到原始问题答案的人了。我只是添加了int*,因为OP要求将X*作为受保护的数据成员。之所以会有获得者,是因为OP说对于一个简单的例子来说,这是可以接受的。diff是一个函数,因为getter确保PointerDerived返回一个int-对于这个简单的示例。这有意义吗?“变量没有定义正确的接口”:对于
    std::pair
    ;-)来说是个坏消息当然,它不是用来作为基类的,所以我真正要争论的是你是否应该说“变量没有定义一个合适的继承接口”或者诸如此类的话。@SteveJessop:hmm,爸爸,用词的选择。当然,它们可以是接口的一部分。我的意思是,由变量组成的接口是无限的,所以不能对它们强制使用不变量。如果这是你想要的,那就公开;如果没有,就私下进行;但是受保护的变量没有什么意义。当然,在某些情况下,它们可能有用(我已经使用过),但并不多。同意,
    pair
    是特殊的,因为根据定义,它的两个成员是独立的。没有类不变量将它们联系起来。@rodrigo“人们可能认为信息隐藏是原理,封装是技术”,正如维基百科所说,我倾向于同意作者的观点。最终意味着同样的事情我也不喜欢受保护,尽量少用。-我喜欢静态getter的想法,尽管,嗯,。。。
    class Base {
    public:
      Base( int m ) : member(m){}
    private:
      int member;
    protected:
      static int GetMember(const Base &b)
      { return b.member; }
    };
    
    class Derived : public Base { // one of several subclasses
    public:
      Derived( int m ) : Base(m), value(10) {}
      int diff( Base &x ){ //beware of your slicing!
        return value - GetMember(x);
      }
    private:
      int value;
    };