What is the meaning of clang's -Wweak-vtables?
I basically do not understand clang's -Wweak-vtables
. Here is what I observed so far:
Case one: (triggers the warning)
class A {
public:
virtual ~A(){}
};
class B : public A {
public:
virtual ~B(){}
};
int main(){}
Case two: (Does not trigger warning)
class A {
public:
virtual ~A(){}
};
int main(){}
Case three: (Does not trigger warning)
class A {
public:
virtual ~A();
};
A::~A(){}
class B : public A {
public:
virtual ~B(){}
};
int main(){}
Case four: (Triggers warning)
class A {
public:
virtual ~A(){}
virtual void fun(){}
};
class B : public A {
public:
virtual ~B(){}
};
int main(){}
Case five: (Does not trigger warning)
class A {
public:
virtual ~A(){}
virtual void fun();
};
class B : public A {
public:
virtual ~B(){}
};
int main(){}
Case six: (Does not trigger warning)
class A {
public:
virtual ~A(){}
virtual void fun(){}
};
class B : public A {};
int main(){}
Case seven: (Does not trigger warning)
class A {
public:
virtual ~A(){}
virtual void fun(){}
};
class B : public A {
public:
virtual void fun(){}
};
int main(){}
The exact warning is
warning: 'A' has no out-of-line virtual method definitions; its vtable
will be emitted in every translation unit [-Wweak-vtables]
So apparently, if I do not declare a non-inline virtual function in a class, it causes some kind of problem if and only if I derive from it and the derived class has a virtual destructor.
Questions:
- Why is this a problem?
- Why does this get fixed by declaring a virtual function? (Warning speaks of definitions)
- Why does the warning not occur when I do not derive from the class?
- Why does the warning not occur when the derived class does not have a virtual destructor?
Solution 1:
If all of a class's virtual
methods are inline, the compiler has no way to select a translation unit in which to place a single shared copy of the vtable — instead, a copy of the vtable has to be placed in each object file that needs it. On many platforms the linker is able to unify these multiple copies, either by discarding duplicate definitions or by mapping all references to one copy, so this is only a warning.
Implementing a virtual
function out-of-line enables the compiler to select the translation unit that implements that out-of-line method as a "home" for the class's implementation details, and places the single shared copy of the vtable in the same translation unit. If multiple methods are out-of-line, an arbitrary choice of method may be made by the compiler so long as that choice is determined only by the class's declaration; for example, GCC chooses the first non-inline method in declaration order.
If you don't override any method of a class, the virtual
keyword has no observable effect, so there's no need for the compiler to emit a vtable for the class. If you do not derive from A
, or if you fail to declare a derived class's destructor virtual
, there are no overridden methods in A
and thus A
's vtable is omitted. If you declare an additional out-of-line virtual
method to suppress the warning and also do something that overrides a method in A
, the implementation of the non-inline virtual
(and its accompanying copy of the vtable) needs to be supplied in a linked translation unit, otherwise linking will fail because the vtable is missing.