为什么派生类可以具有与基类相同的数据成员

Why can the derived class have the same data members from the base class?

本文关键字:基类 数据成员 派生 为什么      更新时间:2023-10-16

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

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

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

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

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<int, double>并访问这两个元素。这里有一个测试程序,可以实现

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

在这里你可以看到,如果没有阴影,使用可变模板会更加困难。此外,get<>std::tuple中的方法也有类似的实现。

在合理的设计中,这不应该是一个问题。如果您有意创建与基础名称相同的成员,则您的设计存在问题。如果您在不知不觉中这样做,您将不会注意到。

另一方面,如果这在语言层面被禁止,他们在不知不觉中部分将成为一个严重的错误。考虑使用从中继承的框架。现在考虑一下,有一个公共接口是有文档记录的,但任何私有的都是没有文档记录的。现在,您需要从一个类型(比如Window)继承,并且您有了这个变量,它有一个漂亮而有意义的名称,这在世界上是有意义的。如果将其添加到类型中,运行编译器只会发现该名称已在基类型中(或层次结构中的某个位置)使用。。。