转换没有智能指针过期的多态对象类型

时间:2016-05-20 07:49:13

标签: c++ polymorphism smart-pointers

class Animal
{
};

class Dog : public Animal
{
};

class Elephant : public Animal
{
};

有动物物品的集合:

std::vector<std::shared_ptr<Animal>> animals;

程序中的某处还有其他共享指针和弱指针,指的是“animals”集合中的对象。

例如,在动物的索引0处有Dog个对象。

std::shared_ptr<Dog>& dog = std::static_pointer_cast<Dog>(animals[0]);

我需要将此对象的类型转换为Elephant。我不能只删除这个对象(Dog),并创建新的(Elephant),因为弱指针将过期,而其他共享指针将引用旧对象,而不是新对象。 我需要这样做,弱指针和其他共享指针仍将引用相同的对象 - 但类型将是不同的(转换)。 所有引用均为Animal类型,因此不会出现Dog引用的情况,但它已经Elephant

我该怎么办?这种做法是否被认为是黑客攻击?

编辑(更多信息):

问题我在游戏中存在。对于游戏需求,我有时需要将动物转化为怪物,将怪物转化为NPC。 问题是有很多对不同演员的引用。例如,一些怪物可以选择另一个怪物的目标(因此怪物拥有指向另一个怪物的弱指针)。我给出的类层次结构只是示例,但对于真实它看起来像这样。演员 - &gt;怪物,动物,NPC,玩家

3 个答案:

答案 0 :(得分:3)

您可以使用另一个间接级别来执行此操作:而不是直接使用Animal,您可以创建以下内容:

class ShiftingAnimal
{
    ShiftingAnimal(std::unique_ptr<Animal> animal){...}
    void shift(std::unique_ptr<Animal> newAnimal){...}
}

并在整个程序中使用std::shared_ptr<ShiftingAnimal>

答案 1 :(得分:1)

您需要一个额外的间接层。创建一个拥有动物指针的包装器:

struct animal_wrapper {
    std::unique_ptr<Animal> handle;
};

std::vector<std::shared_ptr<animal_wrapper>> animals;

现在您可以更改Wrapper::animal指向的对象,指向该包装器的所有共享指针都将保持有效。

答案 2 :(得分:0)

在你的问题中你说:

  

程序中的某处还有其他共享指针和弱指针,指的是“animals”集合中的对象。

但似乎你不想要指向对象的指针,你想要的东西引用可能在不同时间包含不同对象的位置。

可能的解决方案

  1. “程序中的某个地方”你可以使用迭代器而不是对象的共享/弱指针;这样,当您更改向量中特定位置的内容时,您将继续引用正确的对象。这种可行性取决于你对向量的使用:只有你知道使用模式永远不会使迭代器失效时才能这样做(这是非常不可能的)。
  2. 与之前相同,但不是迭代器存储索引。这不太可能是可行的(只要你从不插入中间/更改排序/删除元素,你现在可以负担重新分配)
  3. 添加一个间接级别,如其他答案所示。
  4. 添加间接级别

    这是在其他答案中提出的,是实现目标的最通用方式;我认为没有理由编写新的类/结构。我建议使用std::vector<std::shared_ptr<std::unique_ptr<Animal>>>,即一个共享指针向量,它引用可能在不同时间包含不同对象的位置(或者没有任何对象)。请注意,在两种情况下(plain unique_ptr和wrapper类),附加级别的间接为使用模式添加了一些“怪异”。 Here您可以找到显示这两个选项的代码。

    另请注意,如果您开始使用unique_ptr而不仅仅是shared_ptr,则可能需要为Animal类提供虚拟析构函数(请参阅this other question)。

    希望这有帮助。