在 运行 时间选择 class 成员的类型
Choose type of class members at run time
我正在尝试构建一个包含其他 classes 作为成员的模块化 class,用户可以在 运行 时间指定这些 classes 的类型.我试图用模板来实现它,但意识到这可能不是正确的方法。这是一个最小的工作示例:
#include <iostream>
// One of the modules. Code will consist of multiple of these modules.
template <class T, class U>
class Module1 {
public:
T subModule1;
U subModule2;
};
class Add {
public:
double Apply(double a) {
return a + x;
}
private:
double x = 2.5;
};
class Multiply {
public:
double Apply(double a) {
return a * pi;
}
private:
double pi = 3.14;
};
class Divide {
public:
double Apply(double a) {
return a / pi;
}
private:
double pi = 3.14;
};
int main(int argc, char* argv[])
{
// User input to determine the used submodules
// Here the user decides to use the Add and Multiply submodules.
Module1<Add, Multiply> module1;
std::cout << module1.subModule1.Apply(3) + module1.subModule2.Apply(2) << std::endl;
}
但是我该如何决定应该使用哪个子模块呢?例如,如果用户想要使用 Divide 和 Add,我必须将 Module1 创建为
Module1<Divide, Add> module1;
会有很多不同的子模块,所以用 if 分支代码也是不可能的。我开始怀疑模板是否可行。你知道更好的方法来完成这个吗?请注意,实施也应该非常高效。
模板用于编译时多态,而您需要运行-time多态。
如果您有一组可能的子模块,则可以使用 std::variant
。它基本上是类型安全的 union
:
using SubmoduleVariant = std::variant<Add, Subtract, Multiply, Divide>;
class Module1 {
public:
SubmoduleVariant subModule1;
SubmoduleVariant subModule2;
};
// ...
Module1 m;
if(userInput == 0) { m.subModule1 = Add{}; }
else if(userInput == 1) { m.subModule1 = Subtract{}; }
else if(userInput == 2) { m.subModule1 = Multiply{}; }
else if(userInput == 3) { m.subModule1 = Divide{}; }
如果您事先不知道可能类型的集合,但它们都符合相同的接口,您可以使用 virtual
函数和基类 class.
如果你事先不知道可能的类型集,并且它们不符合相同的接口,你可以使用 std::any
,它基本上是 "an object of any type" 的包装器。
使用简单的多态性。
class Base {
public:
virtual ~Base() = default;
virtual double Apply(double a) = 0;
};
class Add : public Base {
public:
double Apply(double a) override {}
};
class Multiply : public Base {
public:
double Apply(double a) override {}
};
class Module
{
public:
void addModule(std::unique_ptr<Base> module) {
modules.push_back(std::move(module));
}
void Apply(double a) {
for (const auto& module : modules)
module->Apply(a);
}
std::vector<std::unique_ptr<Base>> modules;
}
Module m;
m.addModule(std::make_unique<Add>());
m.addModule(std::make_unique<Divide>());
可能的解决方案是做出所有可能的组合,select正确的组合:
template <typename T1, T2>
void f() {
Module<T1, T2> module;
std::cout << module.subModule1.Apply(3) + module.subModule2.Apply(2) << std::endl;
}
int main()
{
int type1 = userChoice();
int type2 = userChoice();
std::array<void(*)(), 9> fs = {
&f<Add, Add>, &f<Add, Multiply>, &f<Add, Divide>,
&f<Multiply, Add>, &f<Multiply, Multiply>, &f<Multiply, Divide>,
&f<Divide, Add>, &f<Divide, Multiply>, &f<Divide, Divide>,
}
fs[type1 + 3 * type2]();
}
数组甚至可以通过一些元编程来创建。
但我认为简单的多态性(如丹的回答)就足够了。
我正在尝试构建一个包含其他 classes 作为成员的模块化 class,用户可以在 运行 时间指定这些 classes 的类型.我试图用模板来实现它,但意识到这可能不是正确的方法。这是一个最小的工作示例:
#include <iostream>
// One of the modules. Code will consist of multiple of these modules.
template <class T, class U>
class Module1 {
public:
T subModule1;
U subModule2;
};
class Add {
public:
double Apply(double a) {
return a + x;
}
private:
double x = 2.5;
};
class Multiply {
public:
double Apply(double a) {
return a * pi;
}
private:
double pi = 3.14;
};
class Divide {
public:
double Apply(double a) {
return a / pi;
}
private:
double pi = 3.14;
};
int main(int argc, char* argv[])
{
// User input to determine the used submodules
// Here the user decides to use the Add and Multiply submodules.
Module1<Add, Multiply> module1;
std::cout << module1.subModule1.Apply(3) + module1.subModule2.Apply(2) << std::endl;
}
但是我该如何决定应该使用哪个子模块呢?例如,如果用户想要使用 Divide 和 Add,我必须将 Module1 创建为
Module1<Divide, Add> module1;
会有很多不同的子模块,所以用 if 分支代码也是不可能的。我开始怀疑模板是否可行。你知道更好的方法来完成这个吗?请注意,实施也应该非常高效。
模板用于编译时多态,而您需要运行-time多态。
如果您有一组可能的子模块,则可以使用 std::variant
。它基本上是类型安全的 union
:
using SubmoduleVariant = std::variant<Add, Subtract, Multiply, Divide>;
class Module1 {
public:
SubmoduleVariant subModule1;
SubmoduleVariant subModule2;
};
// ...
Module1 m;
if(userInput == 0) { m.subModule1 = Add{}; }
else if(userInput == 1) { m.subModule1 = Subtract{}; }
else if(userInput == 2) { m.subModule1 = Multiply{}; }
else if(userInput == 3) { m.subModule1 = Divide{}; }
如果您事先不知道可能类型的集合,但它们都符合相同的接口,您可以使用 virtual
函数和基类 class.
如果你事先不知道可能的类型集,并且它们不符合相同的接口,你可以使用 std::any
,它基本上是 "an object of any type" 的包装器。
使用简单的多态性。
class Base {
public:
virtual ~Base() = default;
virtual double Apply(double a) = 0;
};
class Add : public Base {
public:
double Apply(double a) override {}
};
class Multiply : public Base {
public:
double Apply(double a) override {}
};
class Module
{
public:
void addModule(std::unique_ptr<Base> module) {
modules.push_back(std::move(module));
}
void Apply(double a) {
for (const auto& module : modules)
module->Apply(a);
}
std::vector<std::unique_ptr<Base>> modules;
}
Module m;
m.addModule(std::make_unique<Add>());
m.addModule(std::make_unique<Divide>());
可能的解决方案是做出所有可能的组合,select正确的组合:
template <typename T1, T2>
void f() {
Module<T1, T2> module;
std::cout << module.subModule1.Apply(3) + module.subModule2.Apply(2) << std::endl;
}
int main()
{
int type1 = userChoice();
int type2 = userChoice();
std::array<void(*)(), 9> fs = {
&f<Add, Add>, &f<Add, Multiply>, &f<Add, Divide>,
&f<Multiply, Add>, &f<Multiply, Multiply>, &f<Multiply, Divide>,
&f<Divide, Add>, &f<Divide, Multiply>, &f<Divide, Divide>,
}
fs[type1 + 3 * type2]();
}
数组甚至可以通过一些元编程来创建。
但我认为简单的多态性(如丹的回答)就足够了。