2010-05-04 8 views
5

implementieren Wie kann ich diese fließend Schnittstelle in C implementieren ++:Wie fließend Schnittstelle mit einer Basisklasse, in C++

class Base { 
public: 
    Base& add(int x) { 
    return *this; 
    } 
} 

class Derived : public Base { 
public: 
    Derived& minus(int x) { 
    return *this; 
    } 
} 

Derived d; 
d.add(1).minus(2).add(3).minus(4); 

Aktuelle Code funktioniert nicht, da Basisklasse nichts über abgeleitete Klasse wissen, usw. Ich wäre sehr dankbar für einen Hinweis/Vorschlag.

+0

Warum würden Sie das tun? Stellt die Basis eine echt polymorphe Basis dar oder nicht - wenn dies nicht eine LSP-Verletzung ist, ist das wahrscheinlich der Grund, warum es schwierig ist. – Stewart

+1

@Stewart - es handelt sich nicht um eine Verletzung von LSP, es sei denn, eine abgeleitete Funktion als Basis für eine Funktion, die eine Basis erwartet, wurde nicht ordnungsgemäß ausgeführt. Das Hinzufügen eines neuen Verhaltens zu Unterklassen ist vollkommen in Ordnung und wird niemals den LSP verletzen. Es ist nur möglich, gegen LSP zu verstoßen, indem bestehendes Verhalten in Base überschrieben wird, sodass es der Schnittstelle nicht länger gehorcht. –

Antwort

10

Make Basisklasse templated. Verwenden Sie den gewünschten Rückgabetyp Basis der Vorlagentyp, wie folgt aus:

template <typename T> 
class Base { 
public: 
    T& add(int x) { 
    return *static_cast<T *>(this); 
    } 
} 

Dann von Base, wie diese Abgeleitete Erbteil

class Derived : public Base<Derived> 

Alternativ (als Antwort auf Noah Kommentar), wenn Sie don‘ t wollen Base ändern, können Sie eine Zwischenklasse verwenden, die das Gussteil führt, wie folgt aus:

template <typename T> 
class Intermediate : public Base { 
public: 
    T& add(int x) { 
    Base::add(x); 
    return *static_cast<T *>(this); 
    } 
} 

Und lassen Abgeleitet vererben Intermediate:

class Derived : public Intermediate<Derived> 
+2

+1. Dies ist auch bekannt als das seltsam wiederkehrende Template Pattern: http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern – tzaman

+1

Beachten Sie, dass jede Funktion, die auf Basis funktioniert, in eine Template-Funktion umgewandelt werden muss, wenn Sie dies tun. –

+0

@Noah, ich habe eine Alternative hinzugefügt, bei der Base nicht geändert werden muss. – Patrick

1

Diese Schnittstelle ist in C++ nicht möglich. Sie müssen entweder minus() eine virtuelle Funktion innerhalb von Base machen oder Nicht-Member-Funktionen verwenden, die irgendeine Art von Typerkennung durchführen.

Ziehen Sie nicht nach oben(), es sei denn, es macht Sinn in Bezug auf Base.

+2

-1 Es ist schwer zu sagen, dass in C++ etwas nicht möglich ist ;-) –

1

Das Problem ist auf Ihrer Funktion

Base& add(int x); 

dies den Bediener ähnlich ist + =(), die auch nahtlos zu arbeiten außer Kraft gesetzt werden müssen.

Sie müssen diese Funktion für die abgeleitete Klasse überschreiben.

class Derived : public Base { 
public: 
    Derived& minus(int x) { 
    return *this; 
    } 
    Derived & add(int x) { 
    return static_cast<Derived &>(this->Base::add(x)); 
    } 
} 

auf diese Weise wird d.add (1) einen Verweis auf d zurückgeben.

+0

und wenn ich 15 abgeleitete Klassen habe, muss ich add() in jedem von ihnen überschreiben? Was, wenn ich die Basis eines Tages ändere, muss ich mich daran erinnern, wer davon kommt? – yegor256

+0

Sie haben Recht, aber der Compiler wird es Ihnen zurückrufen. Wenn Sie Base mithilfe von CRTP ändern können, wie in der akzeptierten Antwort vorgeschlagen, vermeiden Sie es. Dies ist jedoch nicht immer wünschenswert oder möglich (wenn Sie Base beispielsweise nicht besitzen). Beachten Sie auch, dass jetzt alle Funktionen in Base für jeden abgeleiteten Typ dupliziert werden. –

Verwandte Themen