由于在基类和派生类中具有相同的数据成员,它会造成很多混乱,并且需要使用范围解析运算符来解决冲突。那么为什么在 C++ 中允许它呢?任何人都可以告诉我需要这个吗?
3 回答
我不知道确切的动机,但我相信这是少数类似案例的简单延伸,这是不可避免的。例如,考虑多重继承 - 许多基类可能具有相同的成员,并且作为派生类的创建者,您基本上无能为力。对于 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;
}
在这里您可以看到,如果没有遮盖,使用可变参数模板会更加困难。此外,std::tuple 中的 get<> 方法也有类似的实现。
在一个明智的设计中,这不应该是一个问题。如果您故意创建与您的基地同名的成员,那么您的设计就有问题。如果您在不知不觉中这样做,您将不会注意到。
另一方面,如果这在语言层面被禁止,他们不知不觉的部分将成为一个硬错误。考虑使用您从中继承的框架。现在考虑有一个有据可查的公共接口,但任何私有的都是无证的。现在你需要从一个类型(比如 a Window
)继承,并且你拥有这个变量,这个变量有一个美丽而有意义的名字,这在世界上都是有意义的。您将其添加到您的类型中,运行编译器只是发现该名称已在基本类型(或层次结构中的某个位置)中使用...