2015-02-28 6 views
7

Im Hinblick auf frühere Anfragen zu diesem Thema:Clang -Wweak-vtables und rein abstrakte Klasse

Dies ist ein aus der Frage folgen, die ich habe vor kurzem gefragt: clang: no out-of-line virtual method definitions (pure abstract C++ class) und die als Duplikat markiert wurde dieser Frage: What is the meaning of clang's -Wweak-vtables?. Ich glaube nicht, dass das meine Frage beantwortet hat, also konzentriere ich mich auf das, was mich verwirrt und das noch nicht beantwortet wurde.

Mein Szenario:

Ich versuche, den folgenden einfachen C++ Code mit Clang-3.5 zu kompilieren:

test.h:

class A 
{ 
    public: 
    A(); 
    virtual ~A() = 0; 
}; 

test.cc

#include "test.h" 

A::A() {;} 
A::~A() {;} 

Der Befehl, den ich für die Kompilierung verwende (Li Nux, uname -r: 3.16.0-4-amd64):

$clang-3.5 -Wweak-vtables -std=c++11 -c test.cc 

Und die Fehler, die ich bekomme:

./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] 

Der obige Code fein baut, wenn der Klasse A nicht rein abstrakt ist. Der folgende Code erzeugt keine Warnungen, und die einzige Änderung ist, dass die Klasse A ist nicht mehr abstrakt:

test2.h:

class A 
{ 
    public: 
    A(); 
    virtual ~A(); 
}; 

test2.cc

#include "test2.h" 

A::A() {;} 
A::~A() {;} 

Meine Frage

Was ist das Besondere an reinen abstrakten Klassen, dass der obige Code wa auslöst in Clang?

+0

In Ihrem zweiten Beispiel ist 'A' überhaupt nicht abstrakt –

+0

Was denken Sie würde passieren, wenn Sie keine Definition von' A :: ~ A' hätten? Wenn dann der Compiler darauf wartet, eine Definition von'A: ~ A zu sehen, um die VTable zu emittieren, würde es keine VTable geben! – immibis

+1

@immibis das ist richtiges Verhalten, nicht wahr? (andere TUs einschließlich test2.h werden zur gleichen Schlussfolgerung kommen) –

Antwort

4

Eine Klasse mit virtuellen Methoden muss immer eine vtable ausgeben. Der Compiler benötigt eine Angabe, wo die Vtable gespeichert werden soll - normalerweise in dem Objekt, das seine erste Funktion implementiert.

Was ist das Besondere an reine abstrakte Klassen? Da sie keine Methoden haben, muss der Compiler eine vtable in jeder Übersetzungseinheit ausgeben, so dass jede Übersetzungseinheit auf den reinen abstrakten Basistyp verweisen kann. Das sagt dir die Warnung.

Sie können zum Beispiel vorsichtig sein, wenn Sie vermeiden möchten, dass der Speicher in einer Umgebung mit sehr wenig Arbeitsspeicher dupliziert wird, oder wenn Sie die Objekte betrachten und sich fragen, warum es mehrere Kopien der vtable gibt.

In jedem Fall bedeutet die Tatsache, dass Sie einen polymorphen Zeiger auf ein A-Objekt nehmen können, dass der Compiler Informationen über diesen Typ — der Vtable ausgeben muss.

Sie können die Warnung für diesen Block mit Clang's diagnostic pragmas deaktivieren, wenn Sie mögen:

#pragma clang diagnostic push 
#pragma clang diagnostic ignored "-Wweak-vtables" 
class A { 
public: 
    virtual void doSomething() = 0; 
    virtual ~A() = 0; 
}; 
#pragma clang diagnostic pop 

Das Dilemma ist: Entweder machen die Klasse nicht-rein abstrakt, oder die Warnung auszuschalten. Abhängig von Ihren Anforderungen bevorzugen Sie vielleicht das eine oder andere, aber wie bei allen Warnungen sollten Sie es sorgfältig prüfen.

+0

Seit wann haben reine abstrakte Klassen keine Methoden? –

+1

@Andrzej Abstrakte Klasse = mindestens eine rein virtuelle Methode. Reine abstrakte Klasse == Schnittstelle => alle Methoden sind rein virtuell? –

+0

@Ted Ich bin immer noch verwirrt. In meinen beiden Beispielen definiere ich A :: ~ A() (und tatsächlich A :: A()). Wie ist das gleichbedeutend mit _no_ Methoden? Und warum das Löschen des Konstruktors auch das Problem löst: 'Klasse A { public: virtuell ~ A() = 0; }; '(angenommen, dass A :: A() auch in test.cc gelöscht wird)? –