unique_ptr的继承和dynamic_cast

Inheritance and dynamic_cast of unique_ptr

本文关键字:dynamic cast ptr unique 继承      更新时间:2023-10-16

在研究了这个例子之后,我还有一个问题:C++生态系统模拟器(继承)。

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

函数签名中智能指针的指导原则是,当且仅当函数关心智能指针本身时,即函数参与对象生存期管理时,它们才应该出现在那里。

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);

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

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);

然而,我并不认为这"更优雅"。。。