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(){}
情况七:(不触发警告)
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]
很明显,如果我不在类中声明一个非内联虚函数,它会导致一些 当且仅当我从它派生并且派生类具有虚拟析构函数时,才会出现这种问题。
问题:
- 为什么这是个问题?
- 为什么要通过声明一个虚函数来解决这个问题? (警告说 定义)
- 为什么当我不是从类派生时不会出现警告?
- 为什么当派生类没有虚析构函数时不会出现警告?
最佳答案
如果一个类的所有 virtual
方法都是内联的,编译器就无法选择一个翻译单元来放置 vtable 的单个共享拷贝——相反,vtable 的拷贝具有放置在每个需要它的目标文件中。在许多平台上,链接器能够通过丢弃重复定义或将所有引用映射到一个拷贝来统一这些多个拷贝,因此这只是一个警告。
外联实现一个虚
函数使编译器能够选择实现该外联方法的翻译单元作为类实现细节的“家”,并将同一翻译单元中 vtable 的单个共享拷贝。如果多个方法是外联的,编译器可以任意选择方法,只要该选择仅由类的声明决定即可;例如,GCC 选择声明顺序中的第一个非内联方法。
如果您不重写类的任何方法,则 virtual
关键字没有可观察到的效果,因此编译器无需为该类生成 vtable。如果您不是从 A
派生的,或者如果您未能声明派生类的析构函数 virtual
,则 A
中没有重写方法,因此A
的 vtable 被省略。如果您声明一个额外的外联 virtual
方法来抑制警告,并且还执行一些覆盖 A
中的方法的操作,则非内联 的实现>virtual
(及其随附的 vtable 拷贝)需要在链接的翻译单元中提供,否则链接将失败,因为 vtable 丢失。
关于c++ - clang 的 -Wweak-vtables 是什么意思?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44209409/