2016-04-13 18 views
0

Ich habe eine Frage, die nach dem Studium dieses Beispiels bleibt: C++ ecosystem simulator (inheritance).Vererbung und dynamic_cast von unique_ptr

Stellen Sie sich vor, ich habe ein ähnliches Beispiel, wo ich mit der std::unique_ptr arbeiten möchte. Gibt es eine Möglichkeit, das dynamische Casting im folgenden Beispiel auszuführen, ohne auf den rohen Zeiger mit der .get() auf der std::unique_ptr zurückgreifen zu müssen? Ich habe zwei Varianten in den Code: eine (can_eat_1), die es die altmodische Art und Weise tut, und eine, wo ich eine .get() in der dynamic_cast für die ich frage, ob es entfernt und durch eine elegantere Methode ersetzt werden kann (can_eat_2) :

#include <iostream> 
#include <memory> 

struct Animal 
{ 
    virtual ~Animal() {}; 
}; 
struct Carnivore : public Animal {}; 
struct Herbivore : public Animal {}; 

struct Wolf : public Carnivore {}; 
struct Rabbit : public Herbivore {}; 

bool can_eat_1(Animal* predator, Animal* prey) 
{ 
    return (dynamic_cast<Carnivore*>(predator) && dynamic_cast<Herbivore*>(prey)); 
} 

bool can_eat_2(std::unique_ptr<Animal>& predator, std::unique_ptr<Animal>& prey) 
{ 
    return (dynamic_cast<Carnivore*>(predator.get()) && dynamic_cast<Herbivore*>(prey.get())); 
} 

int main() 
{ 
    std::unique_ptr<Animal> wolf (new Wolf ); 
    std::unique_ptr<Animal> rabbit(new Rabbit); 

    std::cout << "Option 1: pass raw pointers:" << std::endl; 
    std::cout << "Wolf eats rabbit = " << can_eat_1(wolf.get(), rabbit.get()) << std::endl; 
    std::cout << "Rabbit eats wolf = " << can_eat_1(rabbit.get(), wolf.get()) << std::endl; 

    std::cout << "Option 2: pass unique_ptr:" << std::endl; 
    std::cout << "Wolf eats rabbit = " << can_eat_2(wolf, rabbit) << std::endl; 
    std::cout << "Rabbit eats wolf = " << can_eat_2(rabbit, wolf) << std::endl; 

    return 0; 
} 

Antwort

2

Der Leitfaden für Smart-Pointer in Funktionssignaturen sind, dass sie genau dann dort erscheinen sollten, wenn die Funktion sich um den Smart Pointer selbst kümmert, das heißt, die Funktion ist an der Verwaltung der Objektlebensdauer beteiligt.

std::unique_ptr<Foo> f();  // Factory (gives an object to the caller) 
void f(std::unique_ptr<Foo> &p); // Factory via output parameter 
void f(std::unique_ptr<Foo> p); // Sink (takes an object from the caller) 

In Ihrem Fall überprüft die Funktion eine Eigenschaft Ihrer Tiere. Ihre Lebensdauer interessiert sie überhaupt nicht. Daher sollte der intelligente Zeiger nicht in seiner Signatur erscheinen.

void f(Foo const &p); // Observe a Foo 
void f(Foo const *p); // Observe a Foo 

die eine des Zeigers oder die Referenz Sie ist eine Frage des Geschmacks verwenden, aber die übliche Wahl ist hier eine Referenz.

+0

Wo finde ich diese Richtlinie? Was du schreibst, ergibt für mich Sinn. – Chiel

+1

@Chiel Sie finden diesen Rat auf [Herb Sutters Website] (https://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/). – Quentin

+0

Der Verweis ist hier ein wenig peinlich, da es entweder einen "try" - und einen "catch" -Block erfordern würde, um eine Ausnahme zu erfassen, die für die Flusssteuerung nicht sehr elegant ist, oder eine Neufassung zurück zum Zeiger. Ich denke, ich werde auf die Hinweise eingehen. – Chiel

0

könnten Sie versuchen, diese über Referenzen:

bool can_eat_3(Animal const& predator, Animal const& prey) 
{ 
    return 
     dynamic_cast<Carnivore*>(&predator) 
     && 
     dynamic_cast<Herbivore*>(&prey); 
} 

und nennen es über:

can_eat_3(*wolf, *rabbit); 
Wenn Sie

dereferenzieren und die Adresse erhalten, können Sie mit can_eat_1 arbeiten, auch:

can_eat_1(&*wolf, &*rabbit); 

aber ich weiß nicht wirklich in Betracht ziehen diese ‚elegantere‘ ...

+0

Vielen Dank für diesen Vorschlag, ich stimme Ihnen zu, dass Gießen Hinweise auf Referenzen, um ihre Adresse wieder zu nehmen ist in der Tat nicht so elegant. – Chiel

+0

Denken Sie auch an Quentins Ratschlag. Damit hat er absolut Recht. Und über die Const-ness (er hat es nicht explizit erwähnt, sondern in seinen Beispielen verwendet). Meine Antwort jedoch angepasst. – Aconcagua