假设我有一个多态对象的集合。我幼稚的示例实现将是这样的:
#include <iostream>
#include <memory>
#include <vector>
struct Parent{
virtual void print() const {std::cout<<name <<"\n";}
std::string name{"parent"};
};
struct ChildA:Parent{
virtual void print() const {std::cout<<name <<descr<<"\n";}
std::string name{"child A"};
std::string descr{" is awesome"};
};
struct ChildB:Parent{
virtual void print() const {std::cout<<name <<"\n";}
std::string name{"child B"};
};
class Collection {
public:
void print(){
for (const auto& entry:data){
entry->print();
}
}
void add_data(std::unique_ptr<Parent> p){
data.emplace_back(std::move(p));
}
private:
std::vector<std::unique_ptr<Parent>> data;
};
int main(){
Collection coll;
coll.add_data(std::make_unique<ChildA>(ChildA()));
coll.add_data(std::make_unique<ChildB>(ChildB()));
coll.print();
}
有没有更优雅的方式?我能以某种方式通过(const)参考吗?我真的不喜欢API中的make_unique。
作为解决方案,我提出了以下建议:
template <typename T>
void add_data(const T& d){
data.emplace_back(std::make_unique<T>(d));
}
可以更自然地使用:
coll.add_data(ChildA())
一个相关的问题是包装器类的构造函数。也许:
class Wrapper{
public:
template <typename T>
Wrapper(const T& p):entry{std::make_unique<T>(p)}{}
template <typename T>
Wrapper(const T&& p):entry{std::make_unique<T>(p)}{}
void print(){
entry->print();
}
private:
std::unique_ptr<Parent> entry;
};
这个问题似乎很普遍,所以我想问:什么是“最佳实践”解决方案?