Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clang -Wweak-vtables and pure abstract class

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?

like image 302
banach-space Avatar asked Feb 28 '15 23:02

banach-space


People also ask

What are interfaces and abstract classes?

The Abstract class and Interface both are used to have abstraction. An abstract class contains an abstract keyword on the declaration whereas an Interface is a sketch that is used to implement a class.

What is pure abstract class in C++?

A pure Abstract class has only abstract member functions and no data or concrete member functions. In general, a pure abstract class is used to define an interface and is intended to be inherited by concrete classes. It's a way of forcing a contract between the class designer and the users of that class.

Does a pure virtual class need a constructor?

Pure virtual functions must not be called from a C++ constructor. As a general rule, you should never call any kind of virtual function in a constructor or destructor because those calls will never go to a more derived class than the currently executing constructor or destructor.

Can abstract class have destructor?

You can create an abstract base class with only a virtual destructor.


1 Answers

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.

like image 97
Ted Percival Avatar answered Sep 28 '22 12:09

Ted Percival