受保护时保护太多

时间:2014-02-08 09:17:27

标签: 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(10) {}
  int diff( Base x ){
    return value - x.member;
  }
private:
  int value;
};

派生访问“x.member”,它在Base类中受到保护,对吧?但编译器标记错误,“Base :: member is protected”。并且,在仔细研究了一下之后,我不得不同意编译器。

这就是问题:如何使这项工作最少,而且信息隐藏的损失最小?

  1. 显然,将“成员”公开编译,但这违背了原意。
  2. 使用Base中的“friend”机制让子类访问“member”(以及其他所有私有和受保护的东西)更糟糕(除了超类与其自己的子类的愚蠢绑定 - 维护噩梦)。 / LI>
  3. 在简单示例中,public int getMember(){return member;是可以接受的。但是如果成员的类型是X *,那么你可以做的最好是公共 const X * getMember(){...}。
  4. 我错过了什么吗?

2 个答案:

答案 0 :(得分:3)

您可以保留受保护的属性,添加您提到的getter函数。对于受保护的指针属性,getter将确保返回int(或大对象的const ref),并且您可以在函数模板中执行差异,然后获取Derived和Base参数(getters给出你计算的值。)

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

int diff( Base x ){
    return value - x.member;
  }

等同于在main中写这个:

Base x; 
cout << x.member << endl;

以下是如何使用您自己建议的选项3解决问题的示例,其中派生类PointerDerived使用指针存储:

#include <iostream>

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

  int getMember() const
  {
      return member; 
  }

protected:
  int member;
};

class Derived : public Base { // one of several subclasses
public:
  Derived( int m ) : Base(m), value(10) {}

  int getValue() const
  {
      std::cout << "protected = " << member << std::endl;
      return value; 
  }

private:
  int value;
};

class PointerDerived : public Base { // one of several subclasses
public:

  PointerDerived( int m ) : Base(m), value(new int (10)) {}

  int getValue() const
  {
      std::cout << "protected = " << member << std::endl;
      return *value; 
  }

  ~PointerDerived()
  {
      delete value; 
      value = nullptr;  
  }

private:
  int* value;
};

template<typename Derived, typename Base>
int diff(const Derived& d, const Base& b)
{
    return d.getValue() - b.getMember(); 
}

using namespace std;

int main(int argc, const char *argv[])
{
    PointerDerived p(23); 
    Base q(1);

    cout << diff(p, q) << endl; 

    return 0;
}

由于nullptr,将程序编译为-std=c++11,或将其更改为NULL

您使diff成为一个函数模板,这样您就不必为每个派生类重载它,并让派生类处理存储并访问它,例如{ {1}}。

答案 1 :(得分:2)

您可以使用静态受保护的访问者:

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 ++访问控制以这种方式工作的想法...

C ++中的访问控制与信息隐藏无关。它是关于封装。也就是说,简单地说,如果使用不正确,您可以过滤掉任何可能破坏该类的成员的访问权。

理想的课程

  • 公共成员不能用于破坏对象。
  • 私人成员知道他们在做什么。

如您所见,在我的计划中,受保护成员几乎没有地方:

  • 受保护的成员用于实现继承接口(如果有)。

受保护成员变量的位置更少。

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