我需要调用一组函数,但是在编译时不知道要调用哪些函数。用户决定他感兴趣的计算类型,然后程序接受该输入,动态创建类,将它们放入向量中并循环调用计算方法以获取每次计算的结果。问题是不同的计算需要不同的参数,因此我实际上不能只为向量中的每个对象调用计算而不明确检查它是什么类型的对象。有办法解决吗?
我有以下班级结构:
class AbstractAB {
virtual double calculate() = 0;
virtual ~AbstractAB() = default;
}
class AbstractA : public AbstractAB {
virtual double calculate(int arg_1) = 0;
}
class A : public AbstractA {
double calculate(int arg_1) override;
}
class AbstractB : public AbstractAB {
virtual double calculate(int arg_1, double arg_2) = 0;
}
class B : public AbstractB {
double calculate(int arg_1, double arg_2) override;
}
std::shared_ptr<AbstractAB> a = std::make_shared<AbstractAB>(A());
std::shared_ptr<AbstractAB> b = std::make_shared<AbstractAB>(B());
std::vector<std::shared_ptr<AbstractAB>> vectr = {a, b};
现在我想为每个类调用方法
calculate()
,但由于每个类采用不同的参数,因此如果不明确检查我正在处理哪个类,我就无法做到这一点。以下是伪代码:
for class in vectr:
class.calculate(arg_1? arg_2? How do i know which to pass?)
我想避免代码异味,但我不知道如何避免。我查看了访问者、命令等,但它们没有解决动态决定传递哪些参数的问题。结构有问题,但我无法真正指出问题所在。请帮忙!
有几种方法可以解决这个问题。
这绝对是经典,因为它非常容易实现。
每个函数都只引用堆栈(比如说
std::stack<double>
)。它将其参数从堆栈中弹出,然后将其结果压入。
传统上,这需要用户编写
1 2 +
,它被处理为 stack.push(1); stack.push(2); add(stack)
。如果您可以将更熟悉的中缀表示法 1 + 2
解析到其语法树中,那么深度优先后序遍历将为您将其展平为反向抛光后缀形式。
这只是通过让每个函数采用相同的单个参数来回避问题。
无论如何,这都是您在解析中缀表示法时自然构建的,因此我们可以直接使用它进行评估。实现起来比较复杂,但也许更直观。
您必须让解析器使用知道如何评估自身的节点来构建语法树。这确实意味着评估将是递归的而不是迭代的,因此您通常可能只有一个根节点。
您的解析器必须将
1 + 2
转换为具有两个子节点 add
和 1
的具体节点 2
。每个节点类型都有一个名称(供解析器识别它)和所需的多个输入,并且该类型的每个实例都将有一个包含 unique_ptr<AbstractAB>
子节点的容器。