With regard to previous questions on this topic:
This a follow up of the question that I've asked recently:
clang: no out-of-line virtual method definitions (pure abstract C++ class)
and which was marked as duplicate of this question: What is the meaning of clang's -Wweak-vtables?. I don't think that that answered my question, so here I'm focusing on the very thing that puzzles me and that hasn't been answered yet.
My scenario:
I'm trying to compile the following simple C++ code using Clang-3.5:
test.h:
class A
{
public:
A();
virtual ~A() = 0;
};
test.cc
#include "test.h"
A::A() {;}
A::~A() {;}
The command that I use for compiling this (Linux, uname -r: 3.16.0-4-amd64):
$clang-3.5 -Wweak-vtables -std=c++11 -c test.cc
And the error that I get:
./test.h:1:7: warning: 'A' has no out-of-line virtual method definitions; its vtable will be emitted in every translation unit [-Wweak-vtables]
The above code builds fine when class A is not pure abstract. The following code doesn't emit warnings, and the only change is that class A is no longer abstract:
test2.h:
class A
{
public:
A();
virtual ~A();
};
test2.cc
#include "test2.h"
A::A() {;}
A::~A() {;}
My question
What's so special about pure abstract classes that the above code triggers warnings in Clang?
A class with virtual methods always needs to emit a vtable. The compiler needs an indication of where to store the vtable - usually in the object that implements its first function.
What's so special about pure abstract classes? Since they have no methods, the compiler has to output a vtable in every translation unit so each translation unit can refer to the pure abstract base type. That's what the warning is telling you.
You might care, for example, if you want to avoid duplicating that memory in a very low memory environment, or if you go looking at the objects and wonder why there are multiple copies of the vtable around the place.
In any case, the fact that you can take a polymorphic pointer to an A
object means that the compiler has to emit some information about that type — the vtable.
Option 1: implement a virtual method, such as the destructor
My preference when creating an abstract base class is to provide an out-of-line virtual destructor; ie. implement A::~A()
in the .cpp file. The downside of a user-declared virtual destructor is that it implicitly deletes the automatically-generated copy- and move-constructors & operators, so you end up needing to redeclare them. According to the rule of five, this results in a base class like this:
A.h:
class A {
public:
A() = default;
A(const A&) = default;
A(A&&) = default;
A& operator=(const A&) = default;
A& operator=(A&&) = default;
virtual ~A();
virtual void doSomething() = 0;
};
A.cpp:
A::~A()
{}
It's technically no longer a pure-abstract base class, but it is functionally identical. You get safe destruction by base pointer, it still allows inherited classes to be copy- and move-constructed, and you avoid duplicate vtables in your binary.
Option 2: disable the warning
You can disable the warning for that block with Clang's diagnostic pragmas if you like:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wweak-vtables"
class A {
public:
virtual void doSomething() = 0;
virtual ~A() = 0;
};
#pragma clang diagnostic pop
That's your dilemma: either make the class non-pure-abstract, or turn off the warning. Depending on your requirements you might prefer one or the other, but as with all warnings you should carefully consider it.