C ++构造函数成员初始化列表,对象切片

时间:2018-03-20 23:36:39

标签: c++ inheritance initialization polymorphism object-slicing

我有两个班级

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的不同派生类,甚至派生自派生类。

是否有对象切片?,

是否有解决方案,或者我需要传递指针(不想要这种方法)?

3 个答案:

答案 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;适合因此得名。