对无状态派生类进行切片是否安全?

时间:2018-03-09 21:32:57

标签: c++ polymorphism

我有一个包含一些数据的类:

struct Base
{
  int a,b,c,d;
};

定义了许多派生类来表示Base的不同类型的生成和操作,例如:

struct AlphaA : public Base
{
  AlphaA():a(2),b(0),c(0),d(1){;}
};

struct AlphaB : public Base
{
  AlphaB():a(2),b(1),c(0),d(1)
    {complex_function(*this);}
};
 // ...many more

生成并处理任何派生对象后,a,b,c,d的状态足以完全代表预期的对象。

现在我需要一个函数来处理vector Base:

void processB (std::vector<Base> & bs);

通常,对于更复杂的派生类,我会将参数作为std::unique_poiner<Base>的向量传递,但在这种情况下,派生类没有成员,它们仅作为临时类型安全接口,并且永远不再需要派生类的原始类型,所以我愿意将派生对象切成一个向量,如:

AlphaA B1;
AlphaB B2;
AlphaA B3;
some_function(B3);
// (...)
std::vector<Base> Bs{B1, B2, B3};
processB(Bs);

在这种情况下切片对象是否安全?在考虑替代解决方案和模式之前,我愿意知道这一点。

(具体来说,我希望派生的案例在算法的某些阶段具有不同的类型,然后再衰减到Base,所以我排除Base的生成函数接受一个类型标志或类似的东西。)

3 个答案:

答案 0 :(得分:3)

我不确定 safe 的含义。切片总是安全的 - 因为它不会导致UB。无论你需要与否,完全取决于你。

话虽如此,我不会使用继承来解决问题。相反,我会有静态成员的类来按照你想要的方式操纵参数。

答案 1 :(得分:2)

切片本质上并不危险。它本身并不会引入未定义的行为(请注意,编译器将阻止您创建抽象类的实例)。当您知道自己正在做什么时,将对象切片是安全的。

答案 2 :(得分:1)

  

但是,在这种情况下,派生类没有成员,它们只作为临时类型安全接口,并且永远不再需要派生类的原始类型,

确保这是真的,双重的,三重的。一般来说,这很少是真的。您有一个原因可以创建派生类型的对象,并且相同的原因会引导您沿着您想要知道对象的派生类型的路径。

但是,如果在确定您不需要派生类型之后进行双重和三次,那么将派生类型对象切片到基类型对象就没有风险。