2016-04-13 18 views
0

Bu örnekte çalıştıktan sonra kalan bir sorum var: C++ ecosystem simulator (inheritance).Benzersiz_ptr'nin devralma ve dynamic_casti

Benzer bir örneğim olduğunu düşünelim, burada std::unique_ptr ile çalışmak istiyorum. std::unique_ptr üzerinde .get() kullanarak ham işaretçi almak zorunda kalmadan, aşağıdaki örnekte dinamik döküm yapmak için bir yolu var mı? Ben kodda iki varyantı koydum: bir (can_eat_1) o eski moda yolu veiçinde bir .get() var nerede bir daha zarif bir yöntemle (can_eat_2) kaldırılıp değiştirilip değiştirilemeyeceğini merak ediyorum :

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

ve üzeri diyoruz:

#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; 
} 

cevap

2

kılavuz akıllı işaretçiler için Fonksiyon imzaları, eğer fonksiyonun akıllı göstericinin kendisinin umurunda, yani fonksiyonun nesne yaşam boyu yönetiminde yer alması durumunda ortaya çıkmalarıdır.

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) 

Durumunuzda, işlev, hayvanlarınızın bir özelliğini kontrol eder. Yaşamları hakkında hiç umurunda değil. Böylece akıllı gösterici imzasında görünmemelidir. pointer veya kullandığınız referans biri zevk meselesidir, ama burada her zamanki seçim bir referans

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

.

can_eat_3(*rabbit, *wolf); 
+0

Bu yönergeyi nereden bulabilirim? Yazdıkların bana mantıklı geliyor. – Chiel

+1

@Chiel Bu tavsiyeyi [Herb Sutter'in web sitesinde] bulabilirsiniz (https://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/). – Quentin

+0

Referans, akış denetimi için çok zarif olmayan bir işaretçiyi veya bir işaretçiyi yeniden işaretlemek için bir "try" ve "catch" bloğu gerektireceğinden biraz garip. Sanırım işaretçiler için gideceğim. – Chiel

0

başvurular üzerinden bu deneyebilirsiniz

can_eat_3(*wolf, *rabbit); 

Eğer çözümlemesi ve adresini almak, siz de can_eat_1 çalışabilirsiniz:

can_eat_1(&*wolf, &*rabbit); 

Ancak, gerçekten bu 'daha şık' düşünmüyoruz ...

+0

Bu öneri için, adreslerini tekrar almak için referanslara işaretçi göstermenin gerçekten çok zarif olmadığını kabul ediyorum. – Chiel

+0

Quentin'in tavsiyelerini de dikkate alın. Bu konuda kesinlikle haklı. Ve yapılışı hakkında (açık bir şekilde bahsetmemişti, ancak örneklerinde kullandı). Yine de cevabımı değiştirdim. – Aconcagua