2016-05-01 10 views
4

Ich habe eine abstrakte Basisklasse wie diese;Verwenden der Basisklasse anstelle des Basiszeigers, um an der abgeleiteten Klasse zu arbeiten

class X { 
public: 
    virtual ~X(){} 
    virtual doSomething() = 0; 
}; 

Dann bin der Umsetzung ich dies mit einigen Klassen wie Y, Z usw. von denen jede ihren eigenen Konstruktor, Destruktor und doSomething Implementierung. In meiner Hauptfunktion tue ich;

int main(){ 
    std::vector<X *> v; 
    X *x1 = new Y(); 
    X *x2 = new Z(); 
    v.push_back(x1); 
    v.push_back(x2); 
    for(auto p : v){ 
     p->doSomething() 
    } 
} 

Dies ruft die entsprechenden DoSomething-Implementierungen wie erwartet auf. Aber mein Problem ist, dass ich Zeiger auf abstrakte Klasse verwende, um eine Hierarchie von abgeleiteten Klassen durch seine Basisklasse zu manipulieren. Dies zwingt mich dazu, neue Instanzen auf dem Heap zu erstellen und diese anschließend manuell zu löschen. Gibt es eine Möglichkeit, so etwas zu tun?

int main(){ 
    std::vector<X> v; 
    Y x1(); 
    Z x2(); 
    v.push_back(x1); 
    v.push_back(x2); 
    for(auto p : v){ 
     p.doSomething() 
    } 
} 

So dass Destruktoren automatisch aufgerufen werden, wenn ich außer Haus bin. Ich weiß, dass ich kein Mitglied der abstrakten Klasse erstellen kann, aber das Verwenden von Zeigern, um das alles zu erreichen, erscheint seltsam. Sicherlich muss es einen Weg geben, dies ohne Zeiger und Neu-Löschen zu tun. Es wäre toll, wenn mir jemand die beste Praxis zeigen würde.

Antwort

5

Sie wollen einen entsprechenden Smart-Pointer verwenden:

std::vector<std::unique_ptr<X>> v; 

v.push_back(std::make_unique<Y>()); 
v.push_back(std::make_unique<Z>()); 

// all done 

(Es gibt natürlich immer noch dynamische Zuweisungen, da Sie nicht eine unbegrenzte Anzahl von unbeschränkten Typen ohne Laufzeit indirection verwalten kann, aber man sollte nie zu manuell denken über eines der dynamischen Management. das Typsystem für Sie die ganze Arbeit tun können.)

+0

Ich bin neugierig, wenn Sie denken, dass 'push_back (make_unique ())' ist besser als 'emplace_back (new Y)'. –

+2

@JohnZwinck: Ja. –

+0

Nun, ich denke, ich hätte das in meinen ersten Kommentar aufnehmen sollen, aber: warum? –

2

Trotz der guten Antwort gepostet von Kerrek SB, die OP nach einer Lösung gefragt (lassen Sie mich sagen) new -freien und es lohnt sich, noch eins hinzuzufügen dafür antworten.


können Sie einen std::reference_wrapper verwenden.
Es folgt eine minimale, Arbeitsbeispiel:

#include<vector> 
#include<functional> 
#include<iostream> 

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

class Y: public X { 
    void doSomething() override { 
     std::cout << "Y" << std::endl; 
    } 
}; 

class Z: public X { 
    void doSomething() override { 
     std::cout << "Z" << std::endl; 
    } 
}; 

int main(){ 
    std::vector<std::reference_wrapper<X>> v; 
    Y x1{}; 
    Z x2{}; 
    v.emplace_back(x1); 
    v.emplace_back(x2) 
    for(X &p : v){ 
     p.doSomething(); 
    } 
} 

Beachten Sie, dass Sie in diesem Fall muss garantieren, dass die Lebensdauer der gespeicherten Objekte, die eine des Vektors überwindet.
Sie werden dieses Problem nicht haben, wenn Sie vorhaben, std::unique_ptr s zu verwenden, wie in einer anderen Antwort von Kerrek SB vorgeschlagen.

+0

Kerrek SB schlägt 'std :: unique_ptr' vor, nicht' std :: shared_ptr'. –

Verwandte Themen