2010-04-22 14 views
19

Beginn der Verwendung von PC-Lint auf einer bestehenden Code-Basis (Angst und Angst).Destruktoren für C++ Interface-ähnliche Klassen

Eine Sache, die es beschwert sich über die folgenden:

class IBatch 
{ 
public: 
    virtual void StartBatch() =0; 
    virtual int CommitBatch() =0; 
}; 

die, wenn sie eine andere Klasse von dieser leitet es zu benutzen, wie eine Schnittstelle

base class 'IBatch' has no destructor 

Also, die Frage: Wenn Sie erstellen Schnittstelle Klassen wie oben, enthalten Sie immer einen virtuellen Destruktor? Warum? (Ist es ein Stil oder ein Kodierungsfehler?)

EDIT: Sollte gesagt haben, dass ich nicht erwarte oder will Benutzer von IBatch zu zerstören, sie sind ein Verbraucher eines Dienstes nur, durch diese Schnittstelle zu einigen externe implementierende Klasse (wenn das einen Unterschied machen würde)

+1

Wie bereits erwähnt, benötigen Sie einen virtuellen DTor. Nur als Randnotiz: COM-Schnittstellen beruhen stattdessen auf 'Release()', was eine virtuelle Methode ist, die zu einem "geeigneten" abgeleiteten DTor umleiten kann. – peterchen

Antwort

5

Wenn virtuelle Funktionen vorhanden sind, muss ein virtueller Destruktor vorhanden sein. Immer. Es spielt keine Rolle, dass es nur eine Interface-Klasse ist - es benötigt immer noch den virtuellen Destruktor.

Entweder das, oder es braucht einen protected nichtvirtuellen Destruktor. Dann können Sie das Objekt nicht mit dem Schnittstellenzeiger löschen.

+1

Sofern der Destruktor nicht geschützt ist (dh Sie verhindern das Löschen über einen Zeiger auf die Schnittstelle). –

+0

@Steve: Hehe - behoben. –

2

Also, die Frage: Wenn Sie Interface-Klassen wie die oben erstellen Sie Sie sind immer einen virtuellen destructor? Warum? (Ist es eine Art oder ein Kodierungsfehler?)

Gut hängt es wirklich ab. Wenn Sie jemals auf einem IBatch-Zeiger löschen aufrufen, wird es wahrscheinlich nicht tun, was Sie erwarten. Natürlich, wenn Sie etwas wie virtuelle Init/Shutdowns oder AddRef/Releases haben, dann ist das nicht wirklich ein Problem.

4

Eine Klasse mit virtuellen Funktionen, aber kein virtueller Destruktor ist verdächtig und wahrscheinlich falsch: siehe eine gute und genauere Erklärung here.

7

Coding Fehler - Der Destruktor für die abgeleitete Klasse wird nie, wenn über Zeiger auf Basisklasse aufgerufen aufgerufen.

Wenn Sie IBatch implementieren und Sie beziehen sich auf Ihre abgeleitete Klasse durch einen Zeiger auf eine Basisklasse (Zeiger auf IBatch) und rufen Sie delete an diesem Zeiger auf Basisklasse Sie mit Speicherleck könnte am Ende, weil der Destruktor für Ihre Die abgeleitete Klasse wird niemals aufgerufen.

Die Grundregel ist, wenn eine Klasse mindestens eine virtual Methode hat, die virtual Destruktor haben muss.

class IBatch 
{ 
    public: 
     virtual void f() = 0; 
}; 

class A : public IBatch 
{ 
    public: 
     void f() {} 
     ~A() {} 
}; 

IBatch * a = new A(); 
a->f(); // calls A::f() 
delete a; // calls IBatch::~IBatch() not A::~A() 
+2

Was ist, wenn ich nicht möchte, dass Benutzer der IBatch-Schnittstelle delete bei mir anrufen - ist das die Stelle, wo die geschützte und nicht-virtuelle Antwort von @James eingeht? – sdg

+0

Was meinst du mit 'mir'? – stefanB

+1

@sdg: Ja. Ein geschützter Destruktor verhindert, dass * andere * Klassen (außerhalb der Klassenhierarchie) delete aufrufen. – Kissaki

0

Compiler setzt Standard destructor, die nicht virtuell ist, was bedeutet, dass ein ‚Löschen‘ auf einem Zeiger auf die virtuelle Basisklasse wird mit einem resultierenden Speicherverlust erfolgreich zu sein. Daher ist es ein Implementierungsfehler, weder Stil noch Codierungsfehler.

+0

Tatsächlich ist das Löschen eines abgeleiteten Objekts mit virtuellen Funktionen durch einen Zeiger auf eine Basisklasse ohne virtuellen Destruktor nicht definiert. Es ist also ein Codierungsfehler, und alles kann passieren, einschließlich eines Speicherlecks, eines Programmabsturzes oder eines Falls von nasalen Dämonen. – KeithB

Verwandte Themen