dra*_*ide 54 c++ polymorphism object-slicing
我想在向量中存储几个类的实例.由于所有类都继承自相同的基类,因此这是可能的.
想象一下这个程序:
#include <iostream>
#include <vector>
using namespace std;
class Base
{
public:
virtual void identify ()
{
cout << "BASE" << endl;
}
};
class Derived: public Base
{
public:
virtual void identify ()
{
cout << "DERIVED" << endl;
}
};
int main ()
{
Derived derived;
vector<Base> vect;
vect.push_back(derived);
vect[0].identify();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我希望它能打印"DERIVED",因为"识别"方法是虚拟的.相反,'vect [0]'似乎是一个'Base'实例,它打印出来
基础
我想我可以写一个我自己的容器(可能是从vector派生的),不知何故能够做到这一点(也许只能拿指针......).我只是想问一下是否有更多的C++ ish方法来做到这一点.我希望完全兼容矢量(只是为了方便其他用户应该使用我的代码).
Alo*_*ave 66
你看到的是对象切片.
您将Derived类的对象存储在一个向量中,该向量应该存储Base类的对象,这会导致对象切片,并且被存储的对象的派生类特定成员被切掉,因此存储在向量中的对象就像基类的对象.
解:
您应该在向量中存储指向Base类对象的指针:
vector<Base*>
Run Code Online (Sandbox Code Playgroud)
通过存储指向Base类的指针,就没有切片,你也可以实现所需的多态行为.
由于您要求C++ish这样做的方法,正确的方法是使用合适的智能指针,而不是在向量中存储原始指针.这将确保您不必手动管理内存,RAII将自动为您执行此操作.
TL; DR:您不应继承可公开复制/可移动的课程.
实际上,在编译时可以防止对象切片:在此上下文中,基础对象不应该是可复制的.
案例1:抽象基础
如果基础是抽象的,那么它就无法实例化,因此您无法体验切片.
案例2:具体基础
如果基础不是抽象的,则可以复制它(默认情况下).你有两个选择:
注意:在C++ 11中,移动操作会导致同样的问题.
// C++ 03, prevent copy
class Base {
public:
private:
Base(Base const&);
void operator=(Base const&);
};
// C++ 03, allow copy only for children
class Base {
public:
protected:
Base(Base const& other) { ... }
Base& operator=(Base const& other) { ...; return *this; }
};
// C++ 11, prevent copy & move
class Base {
public:
Base(Base&&) = delete;
Base(Base const&) = delete;
Base& operator=(Base) = delete;
};
// C++ 11, allow copy & move only for children
class Base {
public:
protected:
Base(Base&&) = default;
Base(Base const&) = default;
Base& operator=(Base) = default;
};
Run Code Online (Sandbox Code Playgroud)