GCC如何处理“Woverloaded-virtual”警告?

20

下面的C++代码我认为是正确的,但当使用"-Woverloaded-virtual"编译时会产生一些警告,这个警告是虚假的还是这段代码确实存在问题?

如果这个警告是虚假的,我该如何避免它?在派生类中定义所有异常虚拟变体可以消除警告,但也许有更好的解决方案。

G++命令:

   g++ -c -Woverloaded-virtual test.cpp 
test.cpp:22:18: warning: ‘virtual void intermediate::exception(const char*)’ was hidden [-Woverloaded-virtual]
test.cpp:32:18: warning:   by ‘virtual void derived::exception()’ [-Woverloaded-virtual]

C++代码

using namespace std;

class base
{
public:

    virtual void exception() = 0;
    virtual void exception(const char*) = 0;
};

class intermediate : public base
{
public:

    virtual void exception()
    {
    cerr << "unknown exception" << endl;
    }

    virtual void exception(const char* msg)
    {
    cerr << "exception: " << msg << endl;
    }
};

class derived : public intermediate
{
public:

    virtual void exception() 
    { 
        intermediate::exception("derived:unknown exception");
    }
};
3个回答

27

这个警告意味着:
当您不使用动态分派时,您的derived类对象只能调用,

 void exception()     

如果你想让派生类对象能够调用基类intermediate中所有同名方法,你需要在derived类中添加以下代码。

同时它将隐藏Base类intermediate的所有同名方法。

 using intermediate::exception;

当然,你是最适合决定这是否是一个问题的人。


如果这个警告是有意为之的,我们该如何抑制它? - Sampath
我不确定,但我猜void exception(const char* msg) = delete;会起作用。编辑:不,删除这样的重载是错误的。但是如果在设计良好的代码中真的有意这样做,我会感到惊讶;您应该能够像处理基类实例一样处理派生类的实例。 - Daniel H
正如其他答案所指出的那样,您可以很好地重新定义它为“private”。 - Daniel H

17

警告是由于您无法在derived类型的对象上调用derived::exception(const char*)(或通过指向derived的指针),即使父类定义它并且它是虚拟的(因此您希望它在derived中可用)。为了消除警告,您需要在derived中公开该成员函数:

class derived : public intermediate 
{ 
public: 
  virtual void exception(const char* msg) {intermediate::exception(msg);}
  virtual void exception()  
  {  
    intermediate::exception("derived:unknown exception"); 
  } 
}; 

如果你不想让其他人看到它,可以将其声明为私有的而没有定义。

class derived : public intermediate 
{ 
public: 
  virtual void exception()  
  {  
    intermediate::exception("derived:unknown exception"); 
  } 
private:
  void exception(const char* tmp);
}; 

更新:经过仔细检查(并如Als所指出的那样)使用指令,你也可以这样做:

class derived : public intermediate 
{ 
public: 
  using intermediate::exception; // imports both declarations from intermediate
  virtual void exception() // will not clash with the imported declaration of the
                           // same signature, but properly overriders the parent
                           // class's defition
  {  
    intermediate::exception("derived:unknown exception"); 
  } 
}; 

在派生类中公开基类函数,操作员所需做的就是添加 using intermediate::exception; - Alok Save
实际上不是的 :) 我原本想在我的原帖中使用 'using',但最终决定不这样做(出于我写了在你的第一条评论后的原因相同,我已经删除了那个评论 -- 因为我觉得它可能会与你的评论产生冲突)。在你的评论(以及我的直觉写作)之后,我再次检查以确保。在发现你是正确的之后,我更新了我的答案,此后我注意到了你的第二条评论和链接。当然你必须相信我的话... 但我会再次更新,这样大家都不会有不快 :) - Attila
无论如何,你的替代方案对于那些陷入困境的老旧C++03编程人员来说非常棒。 - YSC

0
请重新定义类"derived"中的函数:virtual void exception(const char* msg); 现在您的代码将不会出现任何警告。

它将会在没有警告的情况下编译,但是如果有人尝试调用它,你就创建了ODR问题。这些问题可能会表现为链接器错误,通常比编译器警告或错误更难阅读和理解。 - Daniel H
@DanielH:ODR 是什么意思? - gpvos
1
这是“单一定义规则”,但我不知道当我发表评论时在想什么,因为我没有看到ODR违规。 - Daniel H

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接