我有
Base
和Derived
类,我需要通过虚拟成员函数从中获得多态行为foo()
:
#include <iostream>
#include <memory>
class Base {
public:
virtual int foo() const = 0;
};
class Derived : public Base {
public:
int foo() const override { return 42; }
};
std::unique_ptr<Base> clone(Base & base) {
//auto copy = base; // cannot create an abstract type
//return std::make_unique(copy);
return std::make_unique(base);
}
int main() {
auto d = Derived();
auto p = clone(d);
std::cout << p->foo() << '\n';
}
不编译:https://godbolt.org/z/voaGdf1sM
<source>: In function 'std::unique_ptr<Base> clone(Base&)':
<source>:19:28: error: no matching function for call to 'make_unique(Base&)'
19 | return std::make_unique(base);
| ~~~~~~~~~~~~~~~~^~~~~~
在
clone()
之外,我希望能够在整个程序的大部分过程中使用值语义来处理Derived
的实例,但是有一种情况我需要将Derived
的实例添加到集合中(std::vector<std::unique_ptr<Base>>
) 并保留多态性,因此在这种情况下,我需要能够将 unique_ptr
添加到 Derived
对象的新 copys中。因此,我有函数
clone()
,它引用了一个Derived
对象,并打算制作一个副本,然后由一个unique_ptr
拥有,然后返回。
不幸的是,我无法弄清楚如何制作对抽象类型的引用的多态副本,如
Base
.
我不能按值传递参数,然后将隐式副本移动到
unique_ptr
,因为不可能有Base
的实例,我需要多态性。
我研究过使用转发参考,例如:
std::unique_ptr<Base> clone(Base && base) {
return std::make_unique(base);
}
// ...
auto p = clone(std::move(d));
但我不想向调用者公开所有权并要求他们调用
std::move
- 它应该可以自由传递对现有对象的引用并期望 clone
复制它,而不是取得它的所有权.我实际上想要它被复制,并且源对象保持完整并且能够再次使用(例如制作更多副本)。
注意:如果我能让它正常工作,
clone
采取 const Base &
可能会更好,毕竟我出于性能原因通过引用传递。
我在这里想做的是 - 制作一个副本,作为
unique_ptr
管理,而不对调用者强加移动语义 - 甚至可能吗?
我想你正在寻找这样的东西:
#include <iostream>
#include <memory>
class Base {
public:
virtual int foo() const = 0;
virtual std::unique_ptr <Base> clone (void) const = 0;
};
class Derived : public Base {
public:
int foo() const override { return 42; }
std::unique_ptr <Base> clone (void) const override
{
auto result = std::make_unique <Derived> ();
*result = *this;
return result;
}
};
int main() {
auto d = Derived ();
auto p = d.clone ();
std::cout << p->foo() << '\n';
}
我不确定还有什么要说的,虽然你也可以这样做:
Base &base = d;
...
auto p = b.clone ();
我认为这更接近您的要求。
我在 SO 的其他地方遇到的一个部分解决方案是使用模板化
clone()
函数来处理具体类型:
#include <iostream>
#include <memory>
class Base {
public:
virtual int foo() const = 0;
};
class Derived : public Base {
public:
int foo() const override { return 42; }
};
template <typename T>
std::unique_ptr<Base> clone(T const & t) {
return std::make_unique<T>(t);
}
int main() {
auto d = Derived();
auto p = clone(d);
std::cout << p->foo() << '\n';
}
https://godbolt.org/z/GbTz4nb3E
这让
make_unique
在提供的参数上调用复制构造函数,就好像它是 Derived
一样,因为调用者知道具体类型。我不确定如果调用者只有对Base
的引用或指针,这是否仍然有效。