类实例与类指针
声明类实例
类可以在全局变量、PROGRAM、FUNCTION、FUNCTION_BLOCK、其他类和结构体中实例化,也可以作为数组元素类型。
VAR_GLOBAL
GlobalCounter : cCounter;
END_VAR
PROGRAM Main
VAR
Counter : cCounter;
Counters : ARRAY[0..3] OF cCounter;
Wrapper : ST_CounterWrapper;
END_VAR
END_PROGRAM
TYPE ST_CounterWrapper :
STRUCT
Counter : cCounter;
END_STRUCT
END_TYPE
数组中的每个类元素、结构体中的类成员以及类中嵌套的其他类实例都有独立的成员存储。
声明类指针
使用 POINTER TO 声明类指针,使用 ADR() 获取实例地址,使用 ^ 解引用。
VAR
Counter : cCounter;
CounterPtr : POINTER TO cCounter;
Result : DINT;
END_VAR
CounterPtr := ADR(Counter);
Result := CounterPtr^.Add();
也可以为类指针定义类型别名或声明指针数组:
TYPE PCounter : POINTER TO cCounter;
END_TYPE
VAR
Pointers : ARRAY[0..3] OF PCounter;
END_VAR
多态调用
父类指针可以保存派生类实例的地址。通过指针调用被重写的方法时,编译器和运行时会根据实例的实际类型选择派生类实现。
VAR
Derived : cDouble;
BasePtr : POINTER TO cCounter;
Result : DINT;
END_VAR
BasePtr := ADR(Derived);
Result := BasePtr^.Add();
嵌套和链式访问
类实例、结构体成员和类指针可以组合访问:
result1 := wrapper.Counter.Add();
result2 := container.Child.Add();
result3 := container.CounterPtr^.Add();
指针安全
- 类指针应由兼容类型实例的
ADR()地址赋值; - 不要将常量数字直接赋给类指针;
- 不要把
VAR_TEMP临时实例的地址保存到生命周期更长的全局指针中; - 解引用前应确认指针已经指向有效实例;
- 不要在无继承关系的类类型之间强制传递指针。
编译器会阻止无效的常量地址赋值,并对可能造成悬空指针的临时实例地址逃逸给出警告。无效指针解引用可能触发运行时 异常保护。
危险
类指针直接访问 PLC 运行时内存。错误的地址或对象生命周期会造成不可预测的程序行为。优先使用普通类实例和 VAR_IN_OUT 引用参数,仅在确有需要时使用类指针。