我想在没有对象切片的情况下保存基类实例的向量(这样我也可以存储基本子女的实例而无需任何问题),同时保持多态性行为而无需添加列表复制值,而是通过引用。
考虑以下源文件:
#include <iostream>
#include <string>
#include <vector>
#include <memory>
class Entity
{
public:
Entity(){this->edited = false;}
virtual std::string name() = 0;
bool edited;
};
class Player: public Entity
{
public:
Player(): Entity(){}
std::string name(){return "player";}
};
int main()
{
std::vector<Entity*> entities;
Player p;
entities.push_back(&p);
entities.at(0)->edited = true;
Entity* ent = entities.at(0);
std::cout << "ent = " << ent->name() << ", edited = " << ent->edited << ".n";
return 0;
}
我获得以下输出:
ent = player, edited = 1.
当输出显示(通过打印"播放器"并显示'编辑'的更改)时,由于原始指针而保持多态性行为,我能够无问题编辑列表的成员。
澄清我要的内容:我可以使用std :: Reference_wrapper实现完全相同的行为吗?当我尝试使用Reference_wrapper时,无法实现相同的行为,因为需要指针才能实现这种多态性行为?如果Reference_wrappers不是一个可行的替代方案,尽管我知道我添加到向量的播放器的实例是堆栈变量,但使用共享_ptr是明智的吗?在我的特定示例中,由于我希望对向量的成员共享所有权,因此我会赞成共享_ptr。有什么更好的方法可以实现这种行为?
非持有指针在现代C 中很好。但是,如果您的指针是拥有,则最好有一个很好的理由使用原始指针而不是智能指针。即使在最坏的情况下,您仍然应该能够编写自己的智能指针。您的示例是一个非拥有指针。
使用std::reference_wrapper<T>
在这里不会为您带来任何收获。我包括了您的示例,已修改以使用它。请注意,直接操纵矢量中的元素有些烦人。
int main()
{
std::vector<std::reference_wrapper<Entity>> entities;
Player p;
entities.push_back(p);
entities.front().get().edited = true;
Entity & ent = entities.front();
std::cout << "ent = " << ent.name() << ", edited = " << ent.edited << ".n";
return 0;
}
原始指针只是一种工具,就像C 提供的许多其他指针一样。当它是正确的工具时,不要害怕使用。现代C 带来的最重要的变化是,它已经消除了原始指针。经验法则是,如果您必须记住delete
您做错了。
请注意,std::vector<T>::front()
是获得第一个元素的首选方法,并且当您知道索引有效时,不建议使用std::vector::at
。
那里没有错。唯一可能是不好的情况是,当您开始分配实体对象并忘记删除它们时。
std::vector<Entity*> entities;
entities.push_back(new Player());
// Somthing that may throw exception
delete entities.at(0)
这有点不同的问题。