【问题标题】:Why can the derived class have the same data members from the base class?为什么派生类可以具有与基类相同的数据成员?
【发布时间】:2013-08-30 18:38:26
【问题描述】:

由于在基类和派生类中具有相同的数据成员,这会造成很多混乱,并且需要使用范围解析运算符来解决冲突。那么为什么在 C++ 中允许它呢?谁能告诉我需要这个吗?

【问题讨论】:

标签: c++ inheritance data-members


【解决方案1】:

我不知道确切的动机,但我相信这是少数类似案例的简单延伸,这是不可避免的。例如,考虑多重继承——许多基类可能具有相同的成员,并且作为派生类的创建者,您基本上无能为力。对 CRTP 来说更糟糕的是——你不可能知道基类的成员,因为它是任意的。这些案例似乎没有您的问题主题那么令人困惑,而且问题更大,因为不能简单地禁止它们而不削弱某些功能。由于无论如何都必须解决歧义问题,因此使用相同的统一规则处理这种特殊情况似乎是很自然的。

【讨论】:

  • 在某些情况下,您明确希望遮盖,例如在可变参数模板中。与 C++ 中的许多其他功能一样,如果使用得当,它会非常强大。
【解决方案2】:

遮蔽并不总是坏事。阴影非常重要的一个反例是当我们使用可变参数模板(尤其是元组)时

示例:考虑以下元组的过度简化实现。这是我看到如何使用可变参数模板的第一个示例。

template<typename... T> class tuple0;

template<> class tuple0<> {}; // end recursion

template<typename Head, typename... Tail>
 class tuple0<Head, Tail...> : public tuple0<Tail...> {
 public:
 Head head;
};

假设现在我们要创建tuple0&lt;int, double&gt; 并访问这两个元素。这是一个执行此操作的测试程序

int main()
{    
    tuple0<int, double>* t1  = new tuple0<int, double>;
    t1->head = 7; //  set the integer value
    std::cout << "integer: " << t1->head << std::endl; 
    tuple0<double>* t2 = static_cast< tuple0<double>* >(t1);
    t2->head = std::cos(2);  // set the double value
    std::cout <<  "double: " << t2->head << std::endl;
    return 0;
}

在这里您可以看到,如果没有遮盖,使用可变参数模板会更加困难。此外,std::tuple 中的 get 方法也有类似的实现。

【讨论】:

  • 这就是为什么我不同意“在明智的设计中,这不应该成为问题”的说法。在可变参数模板中,遮蔽是最佳实践! :)
  • +1 这告诉我何时需要对类数据成员进行遮蔽
  • 您误解了这句话在合理的设计中这绝不应该成为问题。虽然我会避免让用户首先访问元组内部(通过提供辅助函数,从而打破对我使用的名称的依赖),但这是 get 函数的明智设计,并且阴影是正确的,因此这不是问题。
【解决方案3】:

在明智的设计中,这绝不应该成为问题。如果您有意创建与您的基地同名的成员,那么您的设计就有问题。如果您在不知情的情况下这样做,您将不会注意到。

另一方面,如果这在语言级别被禁止,他们 在不知不觉中部分将成为一个硬错误。考虑使用您从中继承的框架。现在考虑有一个有据可查的公共接口,但任何私有的都是无证的。现在您需要从一个类型(比如Window)继承,并且您拥有这个变量,它有一个美丽而有意义的名称,这在世界上都是有意义的。您将其添加到您的类型中,运行编译器只是发现该名称已在基本类型(或层次结构中的某个位置)中使用...

【讨论】:

  • 我的印象是,您认为遮蔽绝不是一种好的做法,这不是真的。在可变参数模板中,阴影是许多情况下的最佳实践:)
  • @ViniciusMiranda:如果这是你得到的印象,我是一个糟糕的作家。遮蔽是 only 有意义的选项。不仅在通用代码中,甚至在非通用纯 OO 代码中,因为您可能需要使用其他人的代码,而且您甚至可能不知道它们的数据成员的名称(从文档中,您总是可以阅读标题)。会出现冲突,并且要求您避免使用您可能甚至不知道使用过的名称,或者升级到库的新版本并且由于它们使用您使用的新名称而无法编译而无法编译,这将是很奇怪的。
  • Previous 我的印象是您说这是一种不好的做法,但不可避免。我想现在很清楚了。谢谢:)
猜你喜欢
  • 1970-01-01
  • 2013-02-05
  • 1970-01-01
  • 1970-01-01
  • 2022-01-25
  • 1970-01-01
  • 2011-01-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多