美好的一天,
我正在编写一个程序' geocalculator'作为我们大学的任务。我遇到了设计问题。接口包含两个组:A和B.每个组由两个组合框和一个表组成。第一个组合框允许用户在几个参考系统(WGS-84,SK-42,SK-95等)之间进行选择。第二个 - 在大地坐标系,空间坐标系和坐标系之间。该表用于输入一堆点(标签,X(或B),Y(或L),Z(或H))。转换函数涉及许多常量和大量公式。
我的问题是:组织代码,连接组合框和函数以调用适当的转换函数的最佳方法是什么?
让我们来点。我将一个抽象模型(PointsModel)子类化,其中存储了我的所有点。它不知道组合框和算法。组合框在MainWindow类中声明。我的模型有自定义委托:它用于将输入坐标的表示从十六进制(度,分和秒)转换为十进制(十进制度)。我有两个按钮(toolBar上的动作):将点从A转换为B,反之亦然。我想象下一步的过程:
我不想通过" if else"陈述!因为会有大量的条件陈述(如果一个组合框是WGS-84而另一个是SK-42那么这样做,如果一个组合框是SK-42而另一个是WGS- 84然后执行此操作,依此类推,以获得一系列参考系统。)
我对声明函数和相应的仿函数有一些想法。我想以某种方式将这些仿函数附加到组合框中,然后时间来调用一般方法,它会自动将调用重定向到所需的函数。
答案 0 :(得分:0)
您可以通过多种方式处理此问题,但我认为最好的方法是在QComboBox
的每个元素上设置一个仿函数。
执行(QComboBox::addData
)[http://qt-project.org/doc/qt-5/qcombobox.html#addItem]时,您会注意到默认的userData
参数。你可以在这里指定一个仿函数。
当您准备好使用它时,只需致电(QBomboBox::currentData
)[http://qt-project.org/doc/qt-5/qcombobox.html#currentData-prop]即可将其恢复使用。
至于在QVariant
中存储您的仿函数,您可以将仿函数存储在您自己的数组中,只需将索引存储到QVariant
中的该数组中即可直接将仿函数存储为使用QVariant(int typeId, const void * copy)
的空白*。
修改强>
从你的评论中听起来像这样的事情可能是有序的:
将您的函数存储在std::map<std::string, std::map<std::string, std::function<X>>>
中,外部地图的键是from-type,而内部地图的键是to-type。
然后将密钥存储在QComboBox
的{{1}}。
答案 1 :(得分:0)
我将描述两个流行的选择:查找表和事件处理程序(按下按钮)。算法的选择取决于您的计算器实现。
这里的基本原理是你想要一个函数与一个符号相关联。例如,您的解析器想要评估&#39; +&#39;对于堆栈上的表达式。您可以查找与&#39; +&#39;相关联的功能,而不是使用switch
或if-elseif
阶梯。并使用两个表达式执行该函数。
// Synonym for a pointer that accepts two parameters,
// performs an operation, and returns the result as a string.
typedef std::string (*Function_Pointer(const std::string& param1, const std::string& param2))
struct Table_Entry
{
const char * operator_text;
Function_Pointer p_operaton_function;
};
const Table_Entry Operation_Table[] =
{
{"+", Perform_Addition},
{"-", Perform_Subtraction},
{"*", Perform_Multiplication},
};
// Or
typedef std::map<std::string, Function_Pointer> Operation_Container;
//...
Operation_Container operations_map;
operations_map["+"] = Perform_Addition;
operations_map["-"] = Perform_Subtraction;
另一个想法是将计算放在按钮的处理程序中。
void On_Button_Dash(Event& e)
{
result = operand_1 - operand2;
}
另一种方法是为操作创建基类。基类将具有评估或执行操作的抽象方法。为每个操作定义子类。在lexing阶段创建操作类,并存储在指向基类的指针向量中。
你的主循环可能是:
std::vector<Base_Operation *> operations;
for (unsigned int i = 0; i < operations.size(); ++i)
{
operations[i].Evaluate(parameter_1, parameter_2);
}