【问题标题】:How to detect "missing" 'virtual' specifier in declaration of overriding virtual method?如何在覆盖虚拟方法的声明中检测“丢失”“虚拟”说明符?
【发布时间】:2014-11-21 09:16:31
【问题描述】:

假设你有这个Base 类:

class Base
{
public:
    virtual void foo();
};

您可以在派生自Base 的类中覆盖foo()

class Derived : public Base
{
public:
    virtual void foo();
};

但是,如果您在 Derived::foo() 的声明中“忘记”了“virtual”:

class Derived : public Base
{
public:
    void foo();
};

你得到完全相同的语义:Derived::foo() 是虚拟的,尽管没有明确声明。

现在,假设您的编码标准规定在这种情况下应明确提及“virtual”。

你知道检测Derived::foo()声明中缺少的'virtual'的简单方法吗(在Linux + gcc 环境中)?

我不知道任何检测到这一点的 gcc 警告。

【问题讨论】:

  • g++ 功能请求在这里:gcc.gnu.org/bugzilla/show_bug.cgi?id=31397
  • 我想修复损坏的编码标准不是一种选择?这似乎是比破坏编译器匹配更好的方法。
  • clang-modernize 允许在代码中添加override

标签: c++ linux gcc virtual


【解决方案1】:

使用 C++11 override 功能。 如果不合适,编译器会输出警告或错误。

不要依赖容易出错的编码标准,而是让编译器为您进行检查。

要回答下面的 cmets,您必须同时考虑这两种情况:

  1. 如果具有相同签名和名称的基类方法不是虚拟的,则在方法上放置 override 限定符将输出错误。
  2. 如果它在层次结构中没有变为虚拟,它也会输出一个错误。

所以这段代码:

struct A
{
   void foo();
   virtual int bar();
};

struct B : A
{
   virtual void foo(); // If you add override here, it errors, if you forget "virtual" it errors too, later in C
   int bar() override;
};

// Write this for each subclass:
struct C : B
{
   void foo() override; // Fails if B does not have "virtual" keyword
};

同意,这很乏味,因为您必须为每个子类复制所有类的签名(无需通过实现)。所以,如果你想强制你所有的孩子明确地覆盖他们从基类“覆盖”的所有虚拟方法,你需要“禁用”子类对基类的继承,如下所示:

#ifndef CheckVirtual
   #define WITH_BASE(X) : public X
#else
   #define WITH_BASE(X) 
#endif

struct A
{
   virtual int bar();
   virtual void baz();
};

//==== \/ This is the hostile code to test \/ ========
struct B WITH_BASE(A)
{
   virtual int bar();
   void baz();
};
//==== End of hostile code ====



//==== \/ Start of enforcer code, you must have one enforcer header per base class to check for 
// Notice that Enforcer must reproduce interface of A
struct Enforcer : B
{
   int bar() override;
   void baz() override; // Error here if CheckVirtual is defined, since B::baz is not virtual.
};

// Or better, some sugar, if you have plenty of child of A, with some macro magic:
template <typename T>
struct VirtualEnforcer_ : T
{
    #include "Your_A_Interface_Here"
};
#define EnforceVirtual(X) VirtualEnforcer_<X> assertVirtual ## X ()

EnforceVirtual(B);
EnforceVirtual(AnotherChildOfA);

【讨论】:

  • 他问的不是这个
  • 这与所要求的完全相反。那么问题是:如何找到所有丢失的覆盖/最终声明!实际上,派生类中的 virtual 在 c++11 中是混乱的。我们还更改了必须写override 并删除virtual 的编码标准。但这并不是如何找到必须放置 virtualoverride 的所有位置的答案。
  • @Matt McNabb:你说得对,这不是我要问的。也就是说,您能够仅从我的用户名 (user1387866) 推断出 ("he") 我是男性用户,这让我印象深刻:)
  • clang 有一个工具(clang-modernize)可以自动添加override
  • @Klaus:好吧,看看我更新的答案。它解释了如何根据需要调整功能。
猜你喜欢
  • 2011-07-18
  • 2018-04-22
  • 2012-06-19
  • 1970-01-01
  • 1970-01-01
  • 2017-11-15
  • 2012-10-26
  • 2011-11-06
  • 2021-09-24
相关资源
最近更新 更多