c++ - 如何创建将由与其关联的名称调用的对象创建函数?
问题描述
我有一个类继承层次结构:图 -> 圆、点、线、矩形。
我需要创建一个函数,通过与其关联的名称从给定的层次结构中创建一个圆形图形对象。该函数应将 unique_ptr 返回给对象。该函数的参数是对象的名称及其特征(x、y、半径)。向层次结构添加新类时,不应更改功能。
告诉我,我该如何实现这个功能?我不明白
例如 ??:
unique_ptr<Figure> CreateFigure(const std::string& name) {
if (name == "circle")
return make_unique<Circle>();
if (name == "line")
return make_unique<Line>()
解决方案
解决问题的标准方法是使用抽象工厂设计模式。
基于“键”。如名称(例如“Circle”)或 id,如整数“3”,将创建所需的类。
所以,工厂总是有一个“创建”方法,一个容器存储所有“创建”方法。为了存储所有方法,我们经常使用std::map
.
问题始终是,类层次结构中使用的构造函数可能具有不同数量的参数。不幸的是,实现起来并不容易,因为工厂“想要”存储具有相同签名的函数。但这当然可以通过可变参数模板来解决。
请参阅以下解决方案:
#include <iostream>
#include <map>
#include <utility>
#include <any>
// Some demo classes ----------------------------------------------------------------------------------
struct Base {
Base(int d) : data(d) {};
virtual ~Base() { std::cout << "Destructor Base\n"; }
virtual void print() { std::cout << "Print Base\n"; }
int data{};
};
struct Child1 : public Base {
Child1(int d, std::string s) : Base(d) { std::cout << "Constructor Child1 " << d << " " << s << "\n"; }
virtual ~Child1() { std::cout << "Destructor Child1\n"; }
virtual void print() { std::cout << "Print Child1: " << data << "\n"; }
};
struct Child2 : public Base {
Child2(int d, char c, long l) : Base(d) { std::cout << "Constructor Child2 " << d << " " << c << " " << l << "\n"; }
virtual ~Child2() { std::cout << "Destructor Child2\n"; }
virtual void print() { std::cout << "Print Child2: " << data << "\n"; }
};
struct Child3 : public Base {
Child3(int d, long l, char c, std::string s) : Base(d) { std::cout << "Constructor Child3 " << d << " " << l << " " << c << " " << s << "\n"; }
virtual ~Child3() { std::cout << "Destructor Child3\n"; }
virtual void print() { std::cout << "Print Child3: " << data << "\n"; }
};
using UPTRB = std::unique_ptr<Base>;
template <class Child, typename ...Args>
UPTRB createClass(Args...args) { return std::make_unique<Child>(args...); }
// The Factory ----------------------------------------------------------------------------------------
template <class Key, class Object>
class Factory
{
std::map<Key, std::any> selector;
public:
Factory() : selector() {}
Factory(std::initializer_list<std::pair<const Key, std::any>> il) : selector(il) {}
template<typename Function>
void add(Key key, Function&& someFunction) { selector[key] = std::any(someFunction); };
template <typename ... Args>
Object create(Key key, Args ... args) {
if (selector.find(key) != selector.end()) {
return std::any_cast<std::add_pointer_t<Object(Args ...)>>(selector[key])(args...);
}
else return nullptr;
}
};
int main()
{
Factory<int, UPTRB> factory{
{1, createClass<Child1, int, std::string>},
{2, createClass<Child2, int, char, long>}
};
factory.add(3, createClass<Child3, int, long, char, std::string>);
// Some test values
std::string s1(" Hello1 "); std::string s3(" Hello3 ");
int i = 1; const int ci = 1; int& ri = i; const int& cri = i; int&& rri = 1;
UPTRB b1 = factory.create(1, 1, s1);
UPTRB b2 = factory.create(2, 2, '2', 2L);
UPTRB b3 = factory.create(3, 3, 3L, '3', s3);
b1->print();
b2->print();
b3->print();
b1 = factory.create(2, 4, '4', 4L);
b1->print();
return 0;
}
这里一般的创建函数是:
template <class Child, typename ...Args>
UPTRB createClass(Args...args) { return std::make_unique<Child>(args...); }
然后是存储所有创建函数的工厂。
推荐阅读
- angular - rxJS 的 debounceTime 在本地工作时工作,但在构建后它没有按预期工作
- javascript - 如何检查字符串是否与 Mongoose 的数组元素匹配
- python - 为 Ximea 相机设置下采样
- c - 在没有 arduino 的情况下为 atmega32 创建新的电子纸库
- powerbi - 如何平均一列值,同时排除另一列中包含某个值的行?PowerBi
- leaflet - Leaflet Routing Machine 上的语言未切换为法语
- python - 如何在 jupyter 笔记本(VSCode + Python 扩展)中隐藏单元格输出?
- javascript - 当 Share Point 2013 列表中的列为空时,如何隐藏 Null 文本?
- spring-boot - 在 spring-boot 2.1.9.release 中寻找匹配的 CachePublicMetrics
- typescript - 如何为这样的函数定义类型?