编译器不应该对派生类中隐藏的基结构的成员变量发出警告吗?
Posted
技术标签:
【中文标题】编译器不应该对派生类中隐藏的基结构的成员变量发出警告吗?【英文标题】:Shouldn't a compiler raise a warning for member variables of base struct shadowed in derived class(es)? 【发布时间】:2016-12-01 10:37:01 【问题描述】:我不小心用基结构派生的类中的私有成员隐藏了(基)结构的一些成员变量。
结构基 一个;
派生类:公共基础 私人: 一个; ...
在我的情况下这是一个错误,导致了一个鬼鬼祟祟的错误(幸运的是在测试时发现)。 由于我认为故意遮蔽成员真的很少见(如果根本不认为是不好的做法),我想知道为什么编译器至少没有发出警告(好吧,不是错误,因为法律允许遮蔽)?
我使用的编译器是 Microsoft Visual C++ 2015,警告级别 4)。 我想知道其他编译器(即 GCC)是否针对这种情况提供了特定的警告?
【问题讨论】:
gcc 也没有提供警告,但有趣的是,这种行为应该如何与多态性一起工作 我相信,即使没有private
,像在您的示例中那样隐藏变量几乎总是一个错误。我为clang 和gcc 提交了功能请求。
@VittorioRomeo 如果在编写Derived
时a
中不存在Base
,这不是错误。
@Raymond Chen,仅供参考,在我的情况下,Base 中已经存在 a。
@roalz:编译器不会知道导致它在编译代码时看到的情况的历史情况。有一些有效的情况,这是完全安全的。如果不知道这两个类的历史,编译器就无法发出警告。
【参考方案1】:
遮蔽的好坏取决于您引入冲突名称的顺序。
假设你有一个类库,其中一个类是这样的:
struct Base
int a;
;
后来,正在使用您的类库的客户 A 写道:
class DerivedA : public Base
private:
int a;
;
在这种情况下,阴影可能是无意的。客户不小心关注了Base::a
。
但是,假设您还有客户 B,他这样写:
class DerivedB : public Base
private:
int b;
;
到目前为止一切顺利。现在您构建了您的库,使其使用Base
对象,而使用您的库的客户B 构建了一个同时使用Base
和DerivedB
对象的代码体。
几周后,您意识到要获得新功能,您需要向Base
添加新成员。
struct Base
int a;
int b; // new member variable
;
这会给您的图书馆带来问题吗?它会给客户 B 带来问题吗?
不,它不会产生任何问题。
所有使用Base
的代码都将继续使用Base
,它可以使用b
成员来获得新奇的b
功能。即使DerivedB
对象被传递给期望Base
的函数,Derived
正在遮蔽b
的事实对Base
没有影响。使用Base
的函数可以说b
,它将访问Base
成员变量。
同时,客户 B 的所有使用 DerivedB
的代码将继续使用 DerivedB
,当该代码显示 b
时,它会变成 DerivedB::b
,就像以前一样。呸,阴影拯救了这一天!
(当然,如果客户 B 想开始利用新的 b
功能,那么客户 B 必须做额外的工作来解决冲突。但重要的是,阴影并没有创造任何新的现有代码中的问题。)
归根结底,阴影的好坏取决于您引入冲突名称的顺序。这不是编译器能够洞察的。
【讨论】:
是的,这不是编译器可以洞察的东西,但可以肯定的是编译器可以轻松警告的人为错误。如果派生类的开发人员有意并想要阴影,他们可能会忽略或抑制警告。在所有这些情况下,我宁愿发出更多警告而不是不受欢迎的行为...... @roalz 但是库作者如何在库本身中引入警告抑制?警告来自客户 B 的代码,库作者无权访问客户 B 的代码。 恕我直言,因为在“客户”代码中引入了阴影(想要或不想要),因此可能由客户来抑制警告。还是我错过了什么? @roalz 是的,由客户来压制,但这也是对库作者的约束。库作者面临着不进行可能导致现有客户构建中断的更改的压力,并且引入新警告相当于由于-Werror
而导致构建中断。
请注意,即使编译器无法判断,IDE 也可能能够判断阴影的好坏 - 如果您使用 IDE 引入变量。以上是关于编译器不应该对派生类中隐藏的基结构的成员变量发出警告吗?的主要内容,如果未能解决你的问题,请参考以下文章