8

fand ich den folgenden Code in einer Bibliothek:Was ist der Vorteil dieses indirekten Funktionsaufrufs?

class Bar { 
public: 
    bool foo(int i) { 
    return foo_(i); 
    } 
private: 
    virtual bool foo_(int i) = 0; 
}; 

Jetzt bin ich frage mich: Warum Sie dieses indirection verwenden würde? Könnte es Gründe, warum die oben besser als die einfache Alternative wäre:

class Bar { 
public: 
    virtual bool foo(int i) = 0; 
}; 

Antwort

10

Dies ist die Non-Virtual Interface Idiom (NVI). Diese Seite von Herb Sutter hat ein gutes Detail. Wie auch immer, temperieren Sie, was Sie dort lesen mit dem, was die C++ FAQ Lite here und here sagt.

Der Hauptvorteil von NVI ist die Trennung der Schnittstelle von der Implementierung. Eine Basisklasse kann einen generischen Algorithmus implementieren und ihn der Welt präsentieren, während seine Unterklassen die Details des Algorithmus durch virtuelle Funktionen implementieren können. Externe Benutzer werden von Änderungen in den Algorithmusdetails abgeschirmt, besonders wenn Sie später entscheiden, dass Sie Code vor und nach der Verarbeitung hinzufügen möchten.

Der offensichtliche Nachteil ist, dass Sie extra Code schreiben müssen. Auch private virtuelle Funktionen sind für viele Menschen verwirrend. Viele Programmierer denken fälschlicherweise, dass Sie sie nicht außer Kraft setzen können. Herb Sutter scheint private virtuals zu mögen, aber IMHO ist es in der Praxis effektiver, der C++ FAQ Lite Empfehlung zu folgen und sie protected zu machen.

3

Dies ist oft ein Template-Hakenpaar (a.k.a Hotspot) genannt, von Wolfgang Pree geprägt.

Sehen Sie diese PDF, PowerPoint, HTML

Ein Grund für das Erledigen der indirection, wie Sie es nennen, ist, dass die Dinge oft kann/muss Setup vor ein Verfahren sein, und einige cleaing Post ein Methodenaufruf. In den Unterklassen müssen Sie nur ohne dabei die Setup das notwendige Verhalten liefern und Reinigung ...

0

Wenn eine Unterklasse die Definition von foo_ ändern könnte ?, aber die Verbraucher benötigt eine statische Funktion (für Effizienz) ? Oder für ein Delegationsmuster?

2

Dies ist das Vorlagenmuster. Die foo-Methode enthält Code, der von allen Unterklassen ausgeführt werden muss. Es macht mehr Sinn, wenn man es so aussehen:

class Bar { 
public: 
    bool foo(int i) { 
    // Setup/initialization/error checking/input validation etc 
    // that must be done for all subclasses 
    return foo_(i); 
    } 
private: 
    virtual bool foo_(int i) = 0; 
}; 

Es ist schöner als die Alternative, die zu versuchen, sich zu erinnern individuell den gemeinsamen Code in jeder Unterklasse zu nennen. Zwangsläufig macht jemand eine Unterklasse, vergißt aber, den allgemeinen Code zu nennen, was zu einer Anzahl von Problemen führt.