ADA中的多类型继承通过泛型mixins
Posted
技术标签:
【中文标题】ADA中的多类型继承通过泛型mixins【英文标题】:Multiple type inheritance in ADA via generic mixins 【发布时间】:2021-07-05 07:57:53 【问题描述】:为了减少测试和重复代码,我发现了通过泛型混入的多重继承,但我不知道实现这一目标的最佳方法以及最佳实践。
具有以下类层次结构示例(使用diagrams.net 完成):
这是泛型的规范:
generic
type S is abstract tagged private;
package GenericChild is
type GenericChild_T is abstract new S with private;
procedure P_SetGenericAttribute (Self : in out GenericChild_T;
i : Integer);
function F_GetGenericAttribute (Self : GenericChild_T)
return Integer;
private
type GenericChild_T is abstract new S with
record
GenericAttribute : Integer;
end record;
end GenericChild;
对于 Child1 中的泛型实例化:
with Root;
with GenericChild;
package Child1 is
type Child1_T is new Root.Root_T with private;
private
package Child1_G is new GenericChild (Root.Root_T);
type Child1_T is new Child1_G.GenericChild_T with null record;
end package Child1;
我可以毫无问题地使用在 Root_T 类上定义的方法,但是,当我尝试使用我得到的通用方法时:
no selector "P_SetGenericAttribute" for private type "Child1_T" ...
这是我测试过的 main.adb:
with Child1;
procedure Main is
Instance : Child1.Child1_T;
begin
Instance.P_SetRootAttribute(1); --ok
Instance.P_SetGenericAttribute(1); --illegal
end main;
为什么?因为我已经封装了通用包实例化? 在那种情况下,最好的解决方法是什么?在子类中创建公共方法并在方法实现中调用私有通用实例化方法?因为我想将通用实例化保持为私有。通过这样做,我可以设置和获取泛型的属性。
这些是对 child1.ads 执行的更改,适用于我:
with Root;
with GenericChild;
package Child1 is
type Child1_T is new Root.Root_T with private;
procedure P_SetGenericAttribute (Self : in out Child1_T;
i : Integer);
function F_GetGenericAttribute (Self : Child1_T)
return Integer;
private
package Child1_G is new GenericChild (Root.Root_T);
type Child1_T is new Child1_G.GenericChild_T with null record;
end package Child1;
这是完成它并工作的child1.adb,但我不确定它是否是实现它的更好方法,例如重命名或其他:
package body Child1 is
procedure P_SetGenericAttribute (Self : in out Child1_T;
i : Integer) is
begin
Child1_G.GenericChild_T(Self).P_SetGenericAttribute (i);
end P_SetGenericAttribute;
function F_GetGenericAttribute (Self : Child1_T)
return Integer is
i : Integer;
begin
i := Child1_G.GenericChild_T(Self).F_GetGenericAttribute;
return i;
end F_GetGenericAttribute;
end package Child1;
欢迎任何建议和/或最佳做法。
【问题讨论】:
请显示引发“无选择器”错误消息的代码(及其上下文)。包 Child1 的私有部分在那里可见吗? @NiklasHolsti 我已经添加了引发错误的主要内容;这是我对错误的思考,因为我已经封装了泛型实例化,所以我不能真正使用泛型公共方法,因为实例化是私有的,但是 GNAT Studio 将这些泛型方法显示为好像它们是公共的,而 IDE 确实不显示继承的,这是一个错误。 我不明白你到底在说什么“错误”,但显然 Main 没有包 Child1 的私有部分的可见性,因此 Main 仅将 Instance 视为Root_T,GenericChild 中定义的操作在 Main 中是不可见的。 @NiklasHolsti 该错误在 GNAT Studio 中,如您所说,它显示了私有通用实例化的方法,而不是从 Root_T 继承的方法。我认为行为没问题,但我想确认它是否是由于私有实例化或什么引起的,你已经确认了。现在,这个问题通常是如何解决的?因为我想封装通用实例化,但我希望它们的公共方法也可以使用。为在内部调用泛型实例化方法的 Child1_T 类型编写公共方法工作正常,但我不确定是否是通常的方式 @Albatros23 最初的答案似乎是:是的。如果你将泛型的实例放在某个包的私有部分,那么你需要添加公共函数来访问这个泛型实例。但是,为了能够给出更明确的答案,如果您可以为您提到的“通过通用混合进行多重继承”模式添加一些解释性参考和/或显示此模式的实际问题,这将是有帮助的成为一个解决方案。这种“通过通用混入实现多重继承”模式解决的实际问题,至少在我看来,并不完全清楚。 【参考方案1】:
no selector "P_SetGenericAttribute" for private type "Child1_T" ...
您收到此错误的原因是您的实现(GenericChild 实例化的派生)是私有的;您的客户根本看不到类型 是 这样的派生。
但是你有一个更大的问题:Ada 不像你的图那样做多重继承。不过,您可以做多个interface
-types 并从中派生。 或您可以使用generic
和静态多态性。 -- 但是直接的多重继承是行不通的。 (您可以,正如您所提到的,也可以使用 mix-ins,但这些并不是真正的继承。)
【讨论】:
感谢您的回复。我知道 Ada 实现某种多重继承有点棘手。我正在尝试在层次结构中使用混合以减少代码重复并因此进行测试,但我不确定我为“Child1”类实现方法的方式是否是通常的方式,或者它是否是更好的解决方案,例如重命名或其他。 @Albatros23,OOP 不是减少代码的好方法,您要寻找的是泛型。这是一个优秀的视频,它(部分)涵盖了为什么 OOP 不适合代码重用:youtube.com/watch?v=OMPfEXIlTVE 感谢您的视频。我同意你的观点,但不幸的是,OOP 对我来说是强制性的,所以我使用 OOP 减少代码的目标是使用包含实现的通用混合组件,因为它们有助于不重复代码。 @Albatros23,您可能对使用泛型和 OOP/-mixin 的主题感兴趣的三篇论文;尽管它们适用于 Ada83 和 Ada95-design:(1)“Ada 的面向对象编程策略”,[IDA 论文:P-3143]; (2) “Ada 中使用 Mixins 进行面向对象编程”,[DOI: 10.1145/142003.142009]; (3) “Ada83 中的面向对象编程——恢复通用性”,[DOI: 10.1145/122012.122018]。以上是关于ADA中的多类型继承通过泛型mixins的主要内容,如果未能解决你的问题,请参考以下文章