我有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
s添加到Derived
对象的新 * 副本 * 中。因此,我有一个函数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
进行管理,而不对调用者施加移动语义-甚至可能吗?
3条答案
按热度按时间uyhoqukh1#
我觉得你在找这样的东西:
我不知道还有什么可说的,但你也可以这样做:
我觉得这更接近你的要求
Live demo
编辑:根据@eerorika的评论,在
Base
中添加了一个虚拟析构函数,我省略它是多么草率!vq8itlhq2#
Paul's solution中不幸的潜在重复可以通过使用Curiously recurring template pattern来缓解:
k3bvogb13#
我在SO的其他地方遇到的一个部分解决方案是使用模板化的
clone()
函数来处理具体类型:https://godbolt.org/z/GbTz4nb3E
这使得
make_unique
可以像调用Derived
一样调用所提供参数的复制构造函数,因为调用者知 prop 体类型。不过,如果调用者只有Base
的引用或指针,我不确定这是否仍然有效。