跳到主要内容

类实例与类指针

声明类实例

类可以在全局变量、PROGRAMFUNCTIONFUNCTION_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 引用参数,仅在确有需要时使用类指针。