如何创建可接收A_Type/B_Type的通用Ada公共库(不依赖A/B包)
解决方案
在Ada中,要实现不依赖具体类型包(A、B)的通用库,同时支持接收不同类型参数,最适合的方式是利用抽象Tagged类型(Ada的面向对象机制),具体步骤如下:
1. 定义通用库CommonLib
在CommonLib中声明一个抽象Tagged类型作为通用参数的基类,同时定义操作该类型的过程。这样CommonLib无需引入A或B包:
package CommonLib is -- 定义抽象Tagged类型,作为所有可传入DoStuff的类型的基类 type Generic_Type is abstract tagged null record; -- 接收抽象类型的Classwide类型(支持所有派生自Generic_Type的具体类型) procedure DoStuff (Param : Generic_Type'Class); end CommonLib;
如果DoStuff需要访问具体类型的内部字段,还需要在抽象类型中定义抽象操作,让具体类型去实现:
package CommonLib is type Generic_Type is abstract tagged null record; -- 定义抽象操作,由具体类型实现字段访问逻辑 function Get_Access (Self : Generic_Type) return access constant String is abstract; procedure DoStuff (Param : Generic_Type'Class); end CommonLib; package body CommonLib is procedure DoStuff (Param : Generic_Type'Class) is Access_Val : access constant String := Param.Get_Access; begin -- 这里可以使用抽象操作获取的内容进行通用处理 null; end DoStuff; end CommonLib;
2. 修改A、B包的类型定义
让A_Type和B_Type派生自CommonLib中的抽象Tagged类型,这样它们就可以被CommonLib的DoStuff接收。此时A、B包需要引入CommonLib,但CommonLib依然不需要引入A、B:
package A is use CommonLib; type A is tagged null record; -- 原A包的类型,保持不变 type Field_Type is ...; -- 补充Field_Type的定义 -- 让A_Type派生自Generic_Type type A_Type is new Generic_Type with record Field : Field_Type; A_Access : access A; end record; -- 如果需要实现抽象操作(比如上面的Get_Access) overriding function Get_Access (Self : A_Type) return access constant String is begin -- 返回A_Type中A_Access的相关内容,根据实际需求实现 return null; end Get_Access; end A;
package B is use CommonLib; type B is tagged null record; -- 原B包的类型,保持不变 type OtherField_Type is ...; -- 补充OtherField_Type的定义 -- 让B_Type派生自Generic_Type type B_Type is new Generic_Type with record OtherField : OtherField_Type; B_Access : access B; end record; -- 实现抽象操作 overriding function Get_Access (Self : B_Type) return access constant String is begin return null; end Get_Access; end B;
3. 调用方式
此时就可以按照你期望的方式直接调用CommonLib的DoStuff:
with CommonLib; use CommonLib; with A; use A; with B; use B; procedure Main is My_A : A_Type; My_B : B_Type; begin CommonLib.DoStuff(My_A); CommonLib.DoStuff(My_B); end Main;
替代方案:泛型包
如果不需要面向对象的分发逻辑,也可以使用泛型包实现。CommonLib定义为泛型包,由调用方传入具体类型进行实例化:
package CommonLib is generic type T is private; package Generic_Operations is procedure DoStuff (Param : T); end Generic_Operations; end CommonLib; package body CommonLib is package body Generic_Operations is procedure DoStuff (Param : T) is begin -- 通用处理逻辑 null; end DoStuff; end Generic_Operations; end CommonLib;
调用时需要先实例化泛型包:
with CommonLib; use CommonLib; with A; use A; package A_Operations is new Generic_Operations (T => A_Type); procedure Main is My_A : A_Type; begin A_Operations.DoStuff(My_A); end Main;
这种方式的缺点是需要为每个类型单独实例化包,不如抽象Tagged类型的调用方式简洁,但如果DoStuff的逻辑完全不依赖类型内部结构,这种方式也适用。
内容的提问来源于stack exchange,提问作者A.Pissicat
相关产品推荐
相关产品推荐

