2016-04-07 10 views
0

Angenommen, ich habe eine Einstellung mit Abstrakte Klasse ApplicatonBase, die eine unique_ptr auf eine andere abstrakte Klasse Document hat:Factory Method-Muster mit unique_ptr Mitglied einer abstrakten Klasse und Copy-Konstruktor

class ApplicationBase 
{ 
public: 

    void factoryMethod() 
    { 
     _doc->doSomething(); 
    }; 

protected: 
    std::unique_ptr<DocumentBase> _doc; 

}; 

class DocumentBase 
{ 
public: 
    virtual void doSomething() = 0; 
}; 

Nun entwickle ich konkrete Klassen RichDocument und RichApplication wie folgt:

class RichDocument : public DocumentBase 
{ 
public: 
    void doSomething() override 
    { 
     std::cout << "I'm rich document\n"; 
    } 
}; 

class RichApplication : public ApplicationBase 
{ 
public: 
    RichApplication() 
    { 
     _doc = std::unique_ptr<RichDocument>(new RichDocument()); 
    } 

    RichApplication(const RichApplication& other) 
    { 
     /* 
     * TODO: I want to copy the data from other document 
     *  unique_ptr and give it to the current document 
     *  unique_ptr 
     */ 

     //Following crashes as the copy constructor is not known: 
     // error: no matching function for call to ‘RichDocument::RichDocument(DocumentBase&) 
     //_doc.reset(new RichDocument(*other._doc)); 
    } 
}; 

Das Problem liegt im Kopierkonstruktor. Ich möchte die Daten im Copy-Konstruktor im unique_ptr tiefkopieren. Gibt es eine Möglichkeit, das zu tun? Oder sollte ich meine Struktur ändern? Jede Hilfe wäre willkommen.

+0

Sie ein virtuelles definieren 'unique_ptr Document :: Klon () 'Methode. Oder Sie können statische Polymorphie verwenden (zB 'template Klasse Anwendung {...} (beachten Sie, dass der Wechsel zu statischem Polymorphismus eine große Entscheidung ist, die eine völlig andere Art der Strukturierung Ihres Codes erfordert) – enobayram

+0

@enobayram Siehe folgendes übrigens: 'Klasse Document { ... virtuellen std :: unique_ptr clone() const { return std :: unique_ptr (neu Document (* this)); }; }; ' und ' Klasse RichDocument: public DocumentBase { ... virtuelles std :: unique_ptr clone() const { Rückkehr std :: unique_ptr (neues RichDocument (* this)); } }; ' Bit Compiler Fehler: kann kein Objekt vom abstrakten Typ 'DocumentBase' zuordnen. Dies liegt an der reinen virtuellen Funktion. Irgendeine Problemumgehung? –

+0

@enobayram Auch wenn in den obigen Clone-Methoden, ich die Abstraktheit der Klasse entfernen, habe ich den folgenden Fehler: ungültige Kovariante Rückgabetyp für 'virtuelle Std :: unique_ptr RichDocument :: clone() –

Antwort

1

Da Sie RichDocument und RichApplication in der Klassenhierarchie Paarung sind, sollten Sie eine der folgenden Möglichkeiten zu tun, darauf vorbereitet sein:

  • jede Basisdokument übernehmen, wenn ein reiches Dokument oder
  • alle Ablehnen Konstruktion Dokumente außer RichDocument.

Unter der Annahme, dass der einzige Weg _doc ist im Konstruktor von RichApplication, der zweite Ansatz initialisieren sollte gut genug sein:

RichDocument *otherDoc = dynamic_cast<RichDocument*>(other._doc.get()); 
// We created RichDocument in the constructor, so the cast must not fail: 
assert(otherDoc); 
_doc.reset(new RichDocument(*otherDoc)); 
+0

Wozu dient 'dynamic_cast', wenn Sie das Ergebnis nicht prüfen wollen? Warum nicht einfach 'static_cast' verwenden? – enobayram

+0

@enobayram Wenn 'dynamic_cast'' nullptr' zurückgibt, ist ein Absturz in der nächsten Zeile garantiert. Wenn "static_cast" automatisch fehlschlägt, weil der Typ falsch ist, stürzt das Programm möglicherweise an einer anderen Stelle ab. Ich denke, eine explizite Behauptung würde nicht schaden. – dasblinkenlight

+0

Ich wäre mir über den Unfall nicht so sicher. f.x würde in diesem speziellen Fall wahrscheinlich nicht abstürzen, da 'RichDocument' keine Mitglieder hat, so dass der Kopierkonstruktor dem Nullzeiger nicht folgen wird. – enobayram