是否有可能有一个复制构造 class 包含 std::unique_ptr<Base> 避免切片而不 Base 暴露 "clone" 函数?

Is it possible to have a copy constructible class that holds a std::unique_ptr<Base> avoiding slicing without Base exposing a "clone" function?

有没有办法为 class(比如 Copyable 编写一个复制构造函数,其中包含 std::unique_ptrBase class(但实际上是在存储 Derived 个对象。

快速测试显示发生了预期的切片,因为 Copyable 不知道它持有的真实类型。所以我想需要一个 clone 方法,但我想知道是否有办法让编译器以更好的方式处理这个问题?

切片代码:

#include <algorithm>
#include <iostream>
#include <memory>
struct Base
{
  Base(int i = 0) : i(i) {}
  virtual ~Base() = default;
  int i;
  virtual int f() { return i; }
};

struct Derived : Base
{
  Derived() = default;
  virtual int f() override { return 42; }
};

struct Copyable
{
  Copyable(std::unique_ptr<Base>&& base) : data(std::move(base)) {}
  Copyable(const Copyable& other)
  {
    data = std::make_unique<Base>(*other.data);
  }
  std::unique_ptr<Base> data;
};

int main()
{
  Copyable c(std::make_unique<Derived>());
  Copyable c_copy = c;

  std::cout << c_copy.data->f() << '\n';
}

clone代码:

#include <algorithm>
#include <iostream>
#include <memory>
struct Base
{
  Base(int i = 0) : i(i) {}
  virtual ~Base() = default;
  int i;
  virtual int f() { return i; }

  virtual Base* clone() { return new Base(i); }
};

struct Derived : Base
{
  Derived() = default;
  virtual int f() override { return 42; }

  virtual Derived* clone() override { return new Derived(); }

};

struct Copyable
{
  Copyable(std::unique_ptr<Base>&& base) : data(std::move(base)) {}
  Copyable(const Copyable& other)
  {
    data.reset(other.data->clone());
  }
  std::unique_ptr<Base> data;
};

int main()
{
  Copyable c(std::make_unique<Derived>());
  Copyable c_copy = c;

  std::cout << c_copy.data->f() << '\n';
}

显然克隆代码有效。问题是,其中有些东西我想避免:

  1. 原始 new.
  2. 需要成为界面一部分的随机函数。
  3. 这个函数returns一个原始指针。
  4. 此 class 的每个想要可复制的用户都需要调用此函数。

那么,有 "clean" 替代方案吗?

请注意,出于所有显而易见的原因,我想使用智能指针,我只需要深度复制 std::unique_ptr。类似于 std::copyable_unique_ptr,将可选的移动语义与深度复制复制构造函数相结合。这是最干净的方法吗?或者这只会增加混乱?

您当然可以为任何您知道如何静态克隆的对象创建 clone_ptr-class。

它将保存一个指向对象的指针,以及一个指向用于克隆所述对象的函数的指针,可能来自转换无状态 lambda。