如何检测"缺失" '虚拟'覆盖虚拟方法的声明中的说明符?

时间:2014-09-26 11:12:15

标签: c++ linux gcc virtual

假设你有这个Base类:

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

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

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

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

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

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

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

您是否知道在virtual声明中检测丢失的“Derived::foo()”的简单方法(在Linux + gcc环境中)?

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

1 个答案:

答案 0 :(得分:-2)

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

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

要回答以下评论,您必须考虑以下两种情况:

  1. 如果具有相同签名和名称的基类方法不是虚拟的,则在方法上放置 override 限定符将输出错误。
  2. 如果它在层次结构中不是虚拟的,也会输出错误。
  3. 所以这段代码:

    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);