unique_ptr的继承和dynamic_cast

时间:2016-04-13 08:00:41

标签: c++ oop c++11

在研究这个例子之后我还有一个问题:C++ ecosystem simulator (inheritance)

想象一下,我有一个类似的例子,我希望使用std::unique_ptr。有没有办法在下面的示例中进行动态转换,而不必使用.get()上的std::unique_ptr来获取原始指针?我在代码中添加了两个变体:一个(can_eat_1)以旧式方式执行,另一个我在.get()中有一个dynamic_cast,我想知道它是否可以被删除并替换为更优雅的方法(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;
}

2 个答案:

答案 0 :(得分:2)

函数签名中智能指针的指导原则是,当且仅当函数关注智能指针本身时,它们应该出现在那里,也就是说,该函数涉及对象生存期管理。

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)

在您的情况下,该功能会检查您动物的属性。它根本不关心他们的一生。因此,智能指针不应出现在其签名中。

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

您使用的指针或参考中的哪一个是品味问题,但这里通常的选择是参考。

can_eat_3(*rabbit, *wolf);

答案 1 :(得分:0)

你可以通过参考试试这个:

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

并通过以下方式调用:

can_eat_3(*wolf, *rabbit);

如果您取消引用并获取地址,您也可以使用can_eat_1:

can_eat_1(&*wolf, &*rabbit);

但是,我并不认为这更优雅......