我有一个将字符串ID映射到base_object的特定实现的映射。 任何base_object都有一个方法get_id,它返回对象的id。 然后我使用(伪)
填充地图void addToMap(base_object* obj){
make_pair(obj->get_id(),obj);
}
此地图的作用类似于工厂,并且知道使用id返回正确的对象。这是检索特定对象的方法声明:
base_object* get(string id);
所有对象都没有字段,只有多态方法对每个实现都有不同的行为。
我不确定实现此目的的最佳方法是什么。
地图应该是<string,unique_ptr<base_object>>
的地图吗?
在这种情况下,当我使用get返回base_object时,是否可以返回指向base_object的原始指针? (我知道地图会继续生存,以免物体被毁坏?)
或者在这种情况下我应该使用shared_ptr?
此外,由于对象实际上没有任何字段,可能最好返回对象的副本吗?
无论如何,我认为它看起来像是一个糟糕的设计,我无法决定解决这个问题的最佳方法。 我对cpp很新,所以我不太熟悉指针的所有差异和最佳用法......
答案 0 :(得分:1)
您可以使用std::unique_ptr<base_object>
并将const引用返回unique_ptr
。
可能的实施:
struct Data
{
std::map<std::string,std::unique_ptr<base_object>> data;
void add(base_object* obj){
data[obj->get_id()] = std::unique_ptr<base_object>(obj);
}
const std::unique_ptr<base_object>& get(const std::string& id) {
return data.at(id);
}
};
用例示例:
Data data;
data.add(new test1_object{});
data["test1"]->create(); // call a virtual function of base_object
请注意,这不是真正的工厂。如果base_object
的抽象函数应该负责创建您的实际产品,您可以这样做:
struct Factory
{
std::map<std::string,std::unique_ptr<base_object>> workers;
void add(base_object* obj){
data[obj->get_id()] = std::unique_ptr<base_object>(obj);
}
Product create(const std::string& id) {
return data.at(id)->foo(); // call the virtual function here
}
};
Factory factory;
factory.add(new test1_object{});
Product x = factory.create("test1");
答案 1 :(得分:1)
使用unique_ptr<base_object> const &
。这向调用者发出信号,告知它获取的是具有所请求id的唯一对象的句柄。使用shared_ptr
信号表明它可能负责保持对象存活。
此外,不需要map
:您可以根据ID使用订单/哈希的set
或unordered_set
。这样,您就不必两次存储ID。
(你正在实施的东西更像是一个对象池,而不是一个工厂。)
答案 2 :(得分:0)
工厂模式的标准未在启动时填充对象。根本没有任何物品。工厂只知道如何创建新对象。一个可能的实现可以使用地图和注册的静态执行此操作!类的方法(不是对象)。
工厂应始终返回一个新实例,而不是引用或指向已存在对象的指针。应用程序通常不知道如何销毁这种特殊类型的副本而不是自己的实例。
答案 3 :(得分:0)
如何最好地设计您的东西取决于用例和设计约束:
std::atexit
注册它们以进行清理),并让地图只保留一个非拥有的原始指针。typeid
作为密钥(至少是名称字段)而不是自定义字符串。std::function
来获得最大的灵活性?std::unordered_map
已分摊O(1)访问权限,仅std::map
O(ln(n))。