函数指针(typedef)
MQL5 具有 typedef 关键字,可用于描述一种特殊类型的函数指针。
typedef 在 C++ 中有更广泛的应用,而在 MQL5 中,typedef 只用于函数指针。
新类型声明的语法如下:
typedef function_result_type ( *function_type )( [list_of_input_parameters] ) ; |
function_type 标识符定义了一个类型名称,该名称成为指向任意函数的指针的同义词(别名),这类函数返回给定类型 function_result_type 的值,并接受输入参数列表 (list_of_input_parameters)。
例如,我们可以有两个具有相同原型的函数(两个 double 类型的输入参数,结果类型也是 double),它们执行不同的算术运算:加法和减法 (FuncTypedef.mq5)。
double plus(double v1, double v2)
|
它们的通用原型很容易描述为指针用途:
typedef double (*Calc)(double, double); |
该条目将 Calc 类型引入到程序中,使用该条目,你可以定义一个变量/参数,用于存储/传递对具有这种原型的任何函数的引用,包括 plus 和 minus 函数。此为指针类型,因为说明中使用了字符 * (*Calc)。在学习 OOP 的时候,我们会深入学习指针星号的特性。
使用这样的指针类来创建自定义算法是很方便的,这些算法可以根据输入数据动态调用与别名相对应的不同函数。
特别是,我们可以引入一个通用的计算器函数:
double calculator(Calc ptr, double v1, double v2)
|
它的第一个参数是用 Calc 类型声明的。由于这一点,我们可以传递一个带有合适原型的任意函数给它,并因此执行一些操作,而 calculator 函数并不知道这些操作的本质。计算器函数通过将调用委托给指针来实现这一点:ptr(v1, v2)。因为 ptr 是一个函数指针,所以这种语法不仅类似于函数调用,而且实际上调用指针所保存的函数。
注意,我们根据特殊值 NULL(NULL 相当于指针的零)预先检查 ptr 参数。事实是指针可能不指向任何位置,也就是说可能没有被初始化。因此,在脚本中,我们描述了一个全局变量:
Calc calc; |
它没有指针。如果不是针对 NULL 的“保护”,用“空”指针 calc 调用 calculator 会导致运行时错误“函数指针调用无效”。
在第一个参数中使用不同的指针调用 calculator 函数会产生以下结果(显示在注释中):
void OnStart()
|
注意,如果没有显式初始化,所有函数指针都用零值填充。这适用于给定类型的全局变量和局部变量。
用 typedef 定义的指针类型可以从函数中返回,例如:
Calc generator(ushort type)
|
此外,函数指针的类型经常用于回调函数(callback,参见 FuncCallback.mq5)。假设我们有一个执行冗长计算的 DoMath 函数(很可能是在一个单独的 库中实现的)。就用户界面的便利性和友好性而言,向用户显示一个进度指示是很棒的。为此,您可以定义一个特殊类型的函数指针,用于通知已完成工作的百分比 (ProgressCallback),并将此类型的参数添加到 DoMath 函数中。在 DoMath 代码中,应该定期调用传递的函数:
typedef void (*ProgressCallback)(const float percent);
|
然后,发起调用的代码可以定义所需的回调函数,将指向它的指针传递给 DoMath,并随着计算的进行接收更新。
void MyCallback(const float percent)
|
函数指针仅适用于 MQL5 中定义的自定义函数。它们不能指向 MQL5 API 的 内置函数 。