clang's -Wweak-vtables是什么意思?

时间:2014-05-19 20:48:07

标签: c++ clang

我基本上不理解clang的-Wweak-vtables。这是我到目前为止所观察到的:

案例一:(触发警告)

class A {
    public:
    virtual ~A(){}        
};

class B : public A {
    public:
    virtual ~B(){}
};

int main(){}

案例二:(不触发警告)

class A {
    public:
    virtual ~A(){}        
};   

int main(){}

案例三:(不触发警告)

class A {
    public:
    virtual ~A();

};

A::~A(){}

class B : public A {
    public:
    virtual ~B(){}
};

int main(){}

案例四:(触发警告)

class A {
    public:
    virtual ~A(){}
    virtual void fun(){}        
};    

class B : public A {
    public:
    virtual ~B(){}
};

int main(){}

案例五:(不触发警告)

class A {
    public:
    virtual ~A(){}
    virtual void fun();      
};    

class B : public A {
    public:
    virtual ~B(){}
};

int main(){}

案例六:(不触发警告)

class A {
    public:
    virtual ~A(){}
    virtual void fun(){}
};    

class B : public A {};

int main(){}

案例7:(不触发警告)

class A {
    public:
    virtual ~A(){}
    virtual void fun(){}
};    

class B : public A {
    public:
    virtual void fun(){}
};

int main(){}

确切的警告是

warning: 'A' has no out-of-line virtual method definitions; its vtable 
will be emitted in every translation unit [-Wweak-vtables]

显然,如果我没有在类中声明非内联虚函数,它会导致一些 当且仅当我从它派生并且派生类具有虚拟析构函数时才出现问题。

问题:

  1. 为什么这是一个问题?
  2. 为什么通过声明虚函数来解决这个问题? (警告说的 定义)
  3. 为什么在我不从班级派生时不会发出警告?
  4. 为什么在派生类没有虚拟析构函数时不会发生警告?

1 个答案:

答案 0 :(得分:89)

如果所有类的virtual方法都是内联的,则编译器无法选择在其中放置vtable的单个共享副本的转换单元 - 而是vtable的副本必须放在需要它的每个目标文件中。在许多平台上,链接器能够通过丢弃重复的定义或将所有引用映射到一个副本来统一这些多个副本,因此这只是一个警告。

在线外实现virtual函数使编译器能够选择实现该外联方法的翻译单元作为" home"对于类的实现细节,并将vtable的单个共享副本放在同一个翻译单元中。如果多个方法是脱节的,编译器可以选择任意方法,只要该选择仅由类的声明确定;例如,GCC在声明顺序中选择第一个非内联方法。

如果您不覆盖类的任何方法,virtual关键字没有可观察到的影响,因此编译器不需要为该类发出vtable。如果您不是从A派生,或者如果您未能声明派生类的析构函数virtual,则A中没有被覆盖的方法,因此A省略了vtable。如果您声明了一个额外的外行virtual方法来取消警告并执行覆盖A中某个方法的操作,则会实现非内联virtual(及其随附的vtable副本)需要在链接的翻译单元中提供,否则链接将因为缺少vtable而失败。

相关问题