【问题标题】:C++ Constructor member initializer lists, Object SlicingC++ 构造函数成员初始化器列表,对象切片
【发布时间】:2018-03-20 23:36:38
【问题描述】:

我有两门课

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

会有对象切片吗?,

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

【问题讨论】:

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


    【解决方案1】:

    这会导致切片。内置多态性的 C++ 仅适用于指针/引用语义。

    事实上:

    class Foo {
      A a;
    

    这甚至不会编译,因为A 不是一个具体的类。

    要解决这个问题,首先创建virtual ~A(){};,然后将智能指针传递给A。可以是唯一的,也可以是共享的。


    如果您无法使用自己的定制多态性。更简单的方法是将pImpl 智能指针填充为类的私有成员,并在持有类中实现复制/移动语义。 pImpl 可以有一个虚拟接口,包装类只是将行为的不可覆盖部分转发给它。

    可以通过小缓冲区优化甚至限制大小的实例来扩展该技术,以避免堆分配。

    所有这些都比直接使用内置的 C++ 对象模型更难,但它可以带来回报。

    要查看这方面的一个著名示例,请检查 std::function<Sig>,它是一种行为多态的值类型。

    【讨论】:

      【解决方案2】:

      将使用您当前拥有的内容进行对象切片。您在Foo 的构造函数中调用A 复制构造函数,并且没有虚拟构造函数。 拥有A 类型的成员变量只会在Foo 的实例中为A 的实例保留足够的空间。只有指针和引用(实际上是指针)的动态绑定,而不是成员变量。

      你必须使用指针来解决这个问题,或者你可以重新考虑你是否真的需要这样的设置。

      【讨论】:

        【解决方案3】:

        是的,有切片。

        必须进行切片,因为 B 不适合在 A 中,但它是 A 存储在类 Foo 中。 B 部分被“切掉”以适应;因此得名。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-12-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多