为什么一个物体在被推入容器时会失去其多态性?

g24*_*24l 1 c++ polymorphism

child从中派生的对象base

class base
{
    public:
    virtual int get() const { return 0;}
    ~virtual base(){}
    };

    class child : public base
    {
    public:
    virtual int get() const override { return 1; }
};
Run Code Online (Sandbox Code Playgroud)

当加入容器时切成薄片,例如

std::vector<base> bases;
bases.push_back(child());
Run Code Online (Sandbox Code Playgroud)

并且下面的代码返回0

bases.at(0).get();
Run Code Online (Sandbox Code Playgroud)

即使push_back的签名是:

void push_back( const T& value );
void push_back( T && value );
Run Code Online (Sandbox Code Playgroud)

这不应该招致切片的对象.

例如,下面的代码导致bad_cast

dynamic_cast<child &>(bases.at(0))
Run Code Online (Sandbox Code Playgroud)

而与基地的孩子打电话则表现出多态行为

void toto(base const & e)
{
    std::cout << e.get() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

这意味着对象不再是一个孩子; 切片在哪里?实际发生了什么?

是否有可能设置basechild应对放置在容器中并且对象不会失去其多态性?

这是一个基本原理问题,并且已经知道一个对象被复制了,所以请不要建议指针/ shared_ptr,因为这已在其他地方得到解决.

Pet*_*etr 6

切片在哪里?

您的

std::vector<base> bases;
Run Code Online (Sandbox Code Playgroud)

存储普通base对象.你不能在那里添加任何东西,只能添加一个base对象.因此,如果你在那里添加了一个对象,那么它就是一个base对象.如果你传递了另一种类型push_back,它将被转换为base(如果可能的话); 在你的情况下,这意味着切片.我不认为你对切片在std::vector特定实现的函数内部发生的确切位置感兴趣.

是否有可能设置basechild应对放置在容器中并且对象不会失去它的多态性?

为了保持多态性,您需要存储指向bases 1的指针.除了容器之外,还有很多方法可以复制它.最简单的方法是写一些类似的东西

child c;
...
std::vector<base*> v;
v.push_back(new child(c)); // and yes, smart pointers are better
Run Code Online (Sandbox Code Playgroud)

您当然可以添加包装器push_back以避免new每次键入.

1您无法在向量中存储引用,但请参阅此问题以获取更多选项.

  • @Nim你_can_以`std :: reference_wrapper`的形式存储引用. (2认同)
  • @zenith,当然 - 但这是作弊..;)(因为它内部存储了一个指针..) (2认同)