您正在寻找的模式称为 factory 或 abstract factory。您事先并不知道要创建什么对象。因此,用户将输入一些数字,并且依赖于此,您将添加相应的对象并设置其参数。
当然,所有可能的不同类都需要在您的代码之前定义,但它们将在运行时动态晚创建和实例化。
为此,通常使用std::map 或std::unordered 映射。在关键部分,您将存储一个选择器。在您的情况下,用户将输入一个数字,例如 1 或 2 或 3 等等。在映射的值部分,您将存储一个指向创建函数的函数指针。
create 函数将在运行时动态创建一个对象,late。并且因为 create 函数的签名(尤其是返回值)必须是相同的类型,所以我们将使用多态性,并从一个公共基类派生所有您需要的类。
然后我们可以将所有对象作为指向基类的指针存储在容器中,并通过它们的基类指针调用成员函数。
这是一般概念。派生类的构造函数通常会有所不同,因为您希望为每个类传递一组特定的参数。然后它变得更加复杂。但也可以解决:
请参阅下面的,抱歉,更复杂的解决方案示例:
#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()
{
// Define the factory with an initializer list
Factory<int, UPTRB> factory{
{1, createClass<Child1, int, std::string>},
{2, createClass<Child2, int, char, long>}
};
// Add a new entry for the factory
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;
}
可以使用您的选择器和不同的参数调用创建函数。
通过基类指针调用print函数,总会调用正确的函数。
请阅读工厂模式以获得更好的理解。