我有一个包含一些数据的类:
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
的生成函数接受一个类型标志或类似的东西。)
答案 0 :(得分:3)
我不确定 safe 的含义。切片总是安全的 - 因为它不会导致UB。无论你需要与否,完全取决于你。
话虽如此,我不会使用继承来解决问题。相反,我会有静态成员的类来按照你想要的方式操纵参数。
答案 1 :(得分:2)
切片本质上并不危险。它本身并不会引入未定义的行为(请注意,编译器将阻止您创建抽象类的实例)。当您知道自己正在做什么时,将对象切片是安全的。
答案 2 :(得分:1)
但是,在这种情况下,派生类没有成员,它们只作为临时类型安全接口,并且永远不再需要派生类的原始类型,
确保这是真的,双重的,三重的。一般来说,这很少是真的。您有一个原因可以创建派生类型的对象,并且相同的原因会引导您沿着您想要知道对象的派生类型的路径。
但是,如果在确定您不需要派生类型之后进行双重和三次,那么将派生类型对象切片到基类型对象就没有风险。