我有两个班级
class A {
public:
virtual void doStuff() = 0;
};
class B : public A {
int x;
public:
virtual void doStuff() override { x = x*2;} //just example function
};
另一个修改和使用上一个
数据的类class Foo {
A a;
public:
Foo::Foo(A &a_) : a(a_) {}
};
现在我创建对象,并传递给Foo类
B b;
// edit b attributes,
Foo foo(b);
所以在类构造函数的参数列表中我知道没有对象切片的问题,因为它是一个引用,但是在赋值变量a(a_)
的情况下是什么情况?
由于我不知道对象b
将要生存多长时间,我需要制作一份安全副本。我有很多来自A的不同派生类,甚至派生自派生类。
是否有对象切片?,
是否有解决方案,或者我需要传递指针(不想要这种方法)?
答案 0 :(得分:3)
这会导致切片。内置多态的C ++仅适用于指针/引用语义。
事实上:
class Foo {
A a;
甚至不会编译,因为A
不是具体的类。
要解决此问题,请首先制作virtual ~A(){};
,然后将智能指针传递给A
。无论是独特的还是共享的。
如果不能使用您自己的定制多态性。更简单的方法是将pImpl
智能指针填充为类的私有成员,并在保持类中实现复制/移动语义。 pImpl
可以有一个虚拟接口,包装类只是将行为的不可覆盖部分转发给它。
这种技术可以通过小缓冲区优化,甚至是有限大小实例来扩展,以避免堆分配。
所有这一切都比直接使用内置的C ++对象模型更难,但它可以带来回报。
要查看一个着名的示例,请检查std::function<Sig>
,它是一种多态行为的值类型。
答案 1 :(得分:1)
将使用您目前拥有的对象切片。你在A
的构造函数中调用了Foo
拷贝构造函数,并且没有虚拟构造函数。
具有A
类型的成员变量仅在Foo
的实例中为A
的实例保留足够的空间。只有动态绑定指针和引用(它们是引擎盖下的指针),而不是成员变量。
你必须使用指针来解决这个问题,或者你可以重新考虑是否真的需要这样的设置。
答案 2 :(得分:0)
是的,有切片。
必须进行切片,因为B
不适合A
,但它是A
,您要存储在类Foo
中。 B
部分是&#34;切掉&#34;适合因此得名。