多文件完整示例
全 ST 工程使用统一符号表。类、派生类和使用这些类的程序可以拆分到不同的 .st 文件中,编译器会解析跨文件类引用和继承关系。
文件一:基类
counter.st
CLASS cCnt
VAR
CV : DINT;
END_VAR
VAR PUBLIC
Incr : DINT := 3;
END_VAR
METHOD PUBLIC Add : DINT
CV := CV + Incr;
Add := CV;
END_METHOD
METHOD PUBLIC AddTwice : DINT
AddTwice := THIS.Add();
AddTwice := THIS.Add();
END_METHOD
METHOD PUBLIC Drain : DINT
VAR_IN_OUT
Victim : cCnt;
END_VAR
Victim.CV := 0;
Drain := Victim.Add();
END_METHOD
END_CLASS
Drain() 位于 cCnt 类内部,因此可以访问另一个 cCnt 实例的私有成员 CV。
文件二:派生类
double-counter.st
CLASS cDouble EXTENDS cCnt
METHOD PUBLIC OVERRIDE Add : DINT
Add := SUPER.Add() * 2;
END_METHOD
END_CLASS
文件三:程序
main.st
PROGRAM st111
VAR
d : ARRAY[0..1] OF cDouble;
test_array_dispatch : DINT;
END_VAR
test_array_dispatch := d[0].AddTwice() * 100 + d[1].Add();
END_PROGRAM
类数组中的两个元素是相互独立的实例:
d[0].AddTwice()两次动态调用cDouble.Add(),结果为12;d[1].Add()使用另一个实例的初始状态,结果为6;test_array_dispatch = 12 × 100 + 6 = 1206。
该结果同时验证了成员默认初始化、数组实例隔离、THIS 动态匹配、OVERRIDE 重写和 SUPER 父类调用。
编译约束
以下情况会导致编译错误或警告:
| 场景 | 结果 |
|---|---|
| 直接实例化抽象类 | 编译错误。 |
| 非抽象派生类未实现全部抽象方法 | 编译错误。 |
| 类直接或间接循环继承 | 编译错误。 |
没有父类时使用 SUPER | 编译错误。 |
OVERRIDE 方法与父类方 法签名不一致 | 编译错误。 |
| 从类外部访问私有成员 | 编译错误。 |
| 从无继承关系的代码访问保护成员 | 编译错误。 |
| 将常量地址赋给类指针 | 编译错误。 |
| 将临时实例地址保存到长生命周期指针 | 悬空指针警告。 |