我基本上不懂clang的-Wweak-vtables.这是我到目前为止所观察到的:
案例一:(触发警告)
class A {
public:
virtual ~A(){}
};
class B : public A {
public:
virtual ~B(){}
};
int main(){}
Run Code Online (Sandbox Code Playgroud)
案例二:(不触发警告)
class A {
public:
virtual ~A(){}
};
int main(){}
Run Code Online (Sandbox Code Playgroud)
案例三:(不触发警告)
class A {
public:
virtual ~A();
};
A::~A(){}
class B : public A {
public:
virtual ~B(){}
};
int main(){}
Run Code Online (Sandbox Code Playgroud)
案例四:(触发警告)
class A {
public:
virtual ~A(){}
virtual void fun(){}
};
class B : public A {
public:
virtual ~B(){}
};
int main(){}
Run Code Online (Sandbox Code Playgroud)
案例五:(不触发警告)
class A {
public:
virtual ~A(){}
virtual void fun();
};
class B : public A {
public:
virtual ~B(){}
};
int main(){}
Run Code Online (Sandbox Code Playgroud)
案例六:(不触发警告)
class A {
public:
virtual ~A(){}
virtual void fun(){}
};
class B : public A {};
int main(){}
Run Code Online (Sandbox Code Playgroud)
案例七:(不触发警告)
class A {
public:
virtual ~A(){}
virtual void fun(){}
};
class B : public A {
public:
virtual void fun(){}
};
int main(){}
Run Code Online (Sandbox Code Playgroud)
确切的警告是
warning: 'A' has no out-of-line virtual method definitions; its vtable
will be emitted in every translation unit [-Wweak-vtables]
Run Code Online (Sandbox Code Playgroud)
显然,如果我没有在类中声明非内联虚函数,那么当且仅当我从它派生并且派生类具有虚拟析构函数时,它才会导致某种问题.
问题:
Jef*_*tin 96
如果所有类的virtual方法都是内联的,则编译器无法选择在其中放置vtable的单个共享副本的转换单元 - 而是必须将vtable的副本放在需要它的每个目标文件中.在许多平台上,链接器能够通过丢弃重复定义或将所有引用映射到一个副本来统一这些多个副本,因此这只是一个警告.
在线外实现virtual函数使编译器能够选择实现该外联方法的转换单元作为类的实现细节的"主页",并将vtable的单个共享副本放在同一个转换单元中.如果多个方法是脱节的,编译器可以选择任意方法,只要该选择仅由类的声明确定; 例如,GCC在声明顺序中选择第一个非内联方法.
如果不覆盖类的任何方法,则virtual关键字没有可观察的效果,因此编译器不需要为类发出vtable.如果你没有派生A,或者你没有声明派生类的析构函数virtual,那么就没有重写的方法A,因此A省略了vtable.如果您声明一个额外的外联virtual方法来抑制警告并执行覆盖方法的内容A,则virtual需要在链接的翻译单元中提供非内联(及其随附的vtable副本)的实现否则链接将失败,因为缺少vtable.