2012-04-03 17 views
3

ich so etwas wie diese:C++: Referenzen und Fabriken

struct D { 
    virtual void operator() {...}; 
} 
struct D1 : public D { 
    virtual void operator() {...}; 
} 
struct D2 : public D { 
    virtual void operator() {...}; 
} 

void foo(D &d) {...}; 

Und so ist dies in Ordnung, und steuern schön den Lebenszyklus meines D's:

foo(D()); 
foo(D1()); 
foo(D2()); 

Aber ich wähle meine D-Variante an mehreren Stellen, so möchte ich eine einfache Fabrik:

const D& make_D() 
{ 
    // BAD, returning reference to temporary 
    if(is_tuesday()) 
     return D1(); 
    return D2(); 
} 

Statt einen Verweis auf eine temporäre zurückzukehren, konnte ich eine obje zurückkehren ct, aber dann schneide ich in die Basisklasse. Alternativ könnte ich einen Zeiger von meiner Fabrik zurückgeben, aber dann muss der Klient ihn löschen. Andere, kompliziertere Lösungen belasten den Client zusätzlich.

Gibt es eine Möglichkeit, etwas zu schreiben, wie

D& d = make_D(); 
foo(d); 

(oder sogar foo(make_D()))? Das Ziel besteht darin, die Komplexität in die verschiedenen D-Definitionen und in make_D() einzubinden, so dass die Funktionen wie foo() und diejenigen, die diese Funktionen aufrufen, sich nicht darum kümmern müssen.

+0

Hinweis: 'foo (D())' wird nicht kompiliert (nicht unter einem Compiler konform. Selbst VS gibt eine Warnung über nicht standardmäßiges Verhalten aus), da ein temporäres nicht an eine nichtkonstante l-Wert Referenz gebunden werden kann . –

Antwort

5

Der übliche Weg besteht darin, entweder einen Zeiger oder einen intelligenten Zeiger zurückzugeben.

Der Nachteil der Verwendung eines Zeigers besteht darin, den Benutzer seinen Speicher verwalten zu lassen.

Wenn Sie einen intelligenten Zeiger zurückgeben, ist dies kein Problem mehr.

const SmartPtr<D> make_D() 
{ 
    if(is_tuesday()) 
     return SmartPtr(new D1()); 
    return SmartPtr(new D2()); 
} 
5

Leider ist das nicht möglich.

Normalerweise, was ich tue, ist std::unique_ptr zu verwenden (manchmal std::shared_ptr, wenn es nicht möglich ist std::unique_ptr zu verwenden):

typedef std::unique_ptr<D> Dptr; 
Dptr make_D() 
{ 
    Dptr p(nulptr); 

    if(is_tuesday()) 
     p.reset(new D1); 
    else 
     p.reset(new D2); 

    return p; 
} 
0

Erstens, ich bin nicht sicher, ich verstehe. Der Code, den Sie aufgelistet haben, ist nicht legal und wird nicht kompiliert. Sind Sie sicher, dass es nicht ist:

struct D 
{ 
    virtual void operator()() const { /* ... */ } 
}; 

und:

void foo(D const& d) { /* ... */ } 

Aufruf, oder ist wandelbar? (Vermutlich nicht, da Sie keine Argumente übergeben, und Sie das Objekt nach der Verwendung wegwerfen.) Wenn nicht, dann können Sie einfach Verweise auf statische Instanzen zurückgeben. Dies ist die übliche Lösung, die ich verwende. Andernfalls ist es möglich, ein kopierbares Objekt sich polymorph zu verhalten, mit dem Briefumschlag-Idiom, aber es ist ein wenig der Arbeit, und hat erhebliche Laufzeitaufwand, da es normalerweise Klonen des tatsächlichen Objekts für jede Kopie erfordert.