c++ 当我们声明一个与基类成员变量同名的变量时,为什么编译器会生成一个关于隐藏的警告?

3ks5zfa0  于 2023-01-15  发布在  其他
关注(0)|答案(2)|浏览(195)

当我添加-Wshadow标志时,编译器(gcc 12.1.0)为以下代码生成以下警告:

prog.cc: In member function 'void Derived::myfunc()':
prog.cc:16:13: warning: declaration of 'i' shadows a member of 'Derived' [-Wshadow]
   16 |         int i = 3;
      |             ^
prog.cc:8:9: note: shadowed declaration is here
    8 |     int i{2};
      |
class Base
{
private:
    int i{2};
};

class Derived : public Base
{
public:
    void myfunc(void)
    {
        int i = 3;
        std::cout << i << "\n";
    }
};

我想的是:因为我们不能只在myfunc中使用"i"变量(因为这是编译时错误),所以没有必要发出这样的警告。
你知道为什么编译器在这种情况下会给出警告吗?

omhiaaxx

omhiaaxx1#

隐藏与名称查找有关,而与访问规则无关

这是设计使然,尤其是没有考虑访问规则,而是通过影响查找结果来隐藏。

-Wshadow
    • 每当局部变量或类型声明隐藏其他**变量、参数、类型、类成员时发出警告(在C中),或示例变量(在Objective-C中)或者当一个内置函数被隐藏时。注意在C中,如果一个局部变量隐藏了一个显式的typedef,编译器会发出警告,但是如果它隐藏了一个struct/class/enum,编译器不会发出警告。如果这个警告被启用,它还包括所有局部阴影示例。这意味着使用-Wshadow时将忽略-Wno-shadow = local和-Wno-shadow = compatible-local。与-Wshadow = global相同。

被遮蔽的i是经由继承的类成员,并且此外private在名称查找将找到什么的意义上与它被遮蔽的事实正交。

示例

作为一个例子,为什么这可能是有问题的,考虑以下增量,它引入了一个人为的程序中的错误。

在时间N编程:

struct A { 
    // Use 0 to indicate that "all is good"
    static constexpr int kStatusIsGood = 0;
    int status{}; // zero-initializer to 0, oops
};

struct B : A {
    constexpr bool clientIsGood(int status) {
        // warning: declaration of 'status' shadows a member of 'B' [-Wshadow]

        (void)status; // logging, using it somehow

        // Key result of the function
        return status == kStatusIsGood;
    }
};

constexpr int kClientPanic = 42;
static_assert(!B{}.clientIsGood(kClientPanic));

在时间N+1编程

开发人员更改了status参数的名称,但忘记更新函数体,由于查找找到了一个隐藏变量,函数体静默地通过编译:

struct A { 
    // Use 0 to indicate that "all is good"
    static constexpr int kStatusIsGood = 0;
    int status{}; // zero-initializer to 0, oops
};

struct B : A {
    constexpr bool clientIsGood(int client_status) {       
        (void)client_status; // logging, using it somehow

        // Ups, a bug was left here
        return status == kStatusIsGood;
    }
};

constexpr int kClientPanic = 42;
static_assert(B{}.clientIsGood(kClientPanic));  // "all is good :)"
vfwfrxfs

vfwfrxfs2#

基类中的i变量存在于已有的派生类中,函数中又定义了一个同名的变量,函数一进入作用域,名称搜索就终止了,这就是基类中的变量不被使用,而是被声明为隐藏它的原因。

相关问题