为实现方法调用,实际参数(参数)被传递给接口变量。也可以省略参数名称。
根据所声明的访问修饰符,一个方法只能在它自己的命名空间 (INTERNAL
) 内被调用,只能在它自己的编程模块及其派生模块 (PROTECTED
) 内被调用,或者只能在它自己的编程模块 (PRIVATE
) 内被调用。对于PUBLIC
,可以从任何地方调用该方法。
在执行过程中,方法可以直接通过THIS
指针,或通过指定功能块的局部变量,递归调用自身。
方法调用作为虚拟函数调用
由于继承关系,可能会出现虚拟函数调用。
虚拟函数调用使同一个调用能够在运行期间调用程序源代码中的各种方法。
在以下情况中,方法调用是动态绑定的:
-
您可以通过指向功能块的指针调用方法(例如
pfub^.method
)。在这种情况下,指针可以指向功能块类型的实例和所有派生功能块的实例。
-
您可以调用接口变量的方法(例如
interface1.method
)。该接口可引用实现该接口的所有功能块实例。
-
一个方法调用同一功能块的另一个方法。在这种情况下,该方法也可以调用同名派生功能块的方法。
-
方法的调用是通过引用功能块来实现的。在这种情况下,引用可以指向功能块类型的实例和所有派生功能块的实例。
-
您可以将
VAR_IN_OUT
基本功能块类型的变量分配给派生 FB 类型的实例。在这种情况下,变量可以指向功能块类型的实例和所有派生功能块的实例。
示例
重载方法
功能块fub1
和fub2
扩展了功能块fubbase
,并实现了接口interface1
。method1
和method2
。
PROGRAM PLC_PRG VAR_INPUT b : BOOL; END_VAR VAR pInst : POINTER TO fubbase; instBase : fubbase; inst1 : fub1; inst2 : fub2; instRef : REFERENCE to fubbase; END_VAR IF b THEN instRef REF= inst1; (* reference to fub1 *) pInst := ADR(instBase); ELSE instRef REF= inst2; (* reference to fub2 *) pInst := ADR(inst1); END_IF pInst^.method1(); (* If b is TRUE, fubbase.method1 will be called, otherwise fub1.method1 is called *) instRef.method1(); (* If b ist TRUE, fub1.method1 will be called, otherwise fub2.method1 is called*)
假设上例中的fubbase
包含两个方法method1
和method2
,则它会覆盖fub1 method2
,但不会覆盖method1
。method1
的调用过程如下:
pInst^.method1()
;
如果b
为 TRUE,则CODESYS 调用fubbase.method1
。如果没有,则调用fub1.method1
。
额外产出
根据 IEC 61131-3 标准,方法可以像正常功能一样声明附加输出。通过方法调用,可以为附加输出分配变量。
有关详细信息,请参阅 "功能 "主题。
呼叫的语法:
<function block name>.<method name>(<first input name> := <value> (, <further input assignments>)+ , <first output name> => <first output variable name> (,<further output assignments>)+ );
示例
声明
METHOD PUBLIC DoIt : BOOL VAR_INPUT iInput_1 : DWORD; iInput_2 : DWORD; END_VAR VAR_OUTPUT iOutput_1 : INT; sOutput_2 : STRING; ENDVAR
致电
fbInstance.DoIt(iInput_1 := 1, iInput_2 := 2, iOutput_1 => iLocal_1, sOUtput_2 => sLocal_2);
调用方法时,方法输出的值会写入本地声明的输出变量。
即使应用程序处于停止状态,也能调用方法
在设备描述中,可以定义某个功能块实例(库函数块)在每个任务周期中始终调用某个方法。如果方法包含下面示例中的输入参数,即使活动应用程序目前处于停止状态,CODESYS 也会处理该方法:
示例
VAR_INPUT pTaskInfo : POINTER TO DWORD; pApplicationInfo: POINTER TO _IMPLICIT_APPLICATION_INFO; END_VAR (*Now the status of the application can be queried via pApplicationInfo and the instructions can be implemented: *) IF pApplicationInfo^.state = RUNNING THEN <instructions> END_IF;
递归调用方法
递归主要用于处理递归数据类型,如链接列表。通常,我们建议您在使用递归时小心谨慎。意外的深度递归可能导致堆栈溢出,从而导致机器停机。
在实现过程中,方法可以调用自身:
-
直接使用
THIS
指针 -
通过基本功能块的本地功能块实例间接实现
通常,编译器会对这种递归调用发出警告。如果提供的方法带有 pragma{attribute 'estimated-stack-usage' := '<sstimated_stack_size_in_bytes>'}
,那么编译器警告就会被抑制。有关实施示例,请参阅 "属性'估计堆栈使用量'"一节。