Ada中的动态调度

Ada中的动态调度,ada,Ada,即使是这个简单的例子,我也很难让动态调度工作。我相信问题在于我如何设置类型和方法,但看不到在哪里 with Ada.Text_Io; procedure Simple is type Animal_T is abstract tagged null record; type Cow_T is new Animal_T with record Dairy : Boolean; end record; procedure Go_To_Vet (A : in

即使是这个简单的例子,我也很难让动态调度工作。我相信问题在于我如何设置类型和方法,但看不到在哪里

with Ada.Text_Io;
procedure Simple is

   type Animal_T is abstract tagged null record;

   type Cow_T is new Animal_T with record
      Dairy : Boolean;
   end record;

   procedure Go_To_Vet (A : in out Cow_T) is
   begin
      Ada.Text_Io.Put_Line ("Cow");
   end Go_To_Vet;

   type Cat_T is new Animal_T with record
      Fur : Boolean;
   end record;

   procedure Go_To_Vet (A : in out Cat_T)
   is
   begin
      Ada.Text_Io.Put_Line ("Cat");
   end Go_To_Vet;

   A_Cat : Cat_T := (Animal_T with Fur => True);
   A_Cow : Cow_T := (Animal_T with Dairy => False);
   Aa : Animal_T'Class := A_Cat;
begin

   Go_To_Vet (Aa); -- ERROR This doesn't dynamically dispatch!
end Simple;
两件事:

首先,您必须有一个Go_to_Vet的抽象规范,这样才能进行委托(这也吸引了我好几次:-):

第二个是Ada要求父定义在其自己的包中:

package Animal is

   type Animal_T is abstract tagged null record;

   procedure Go_To_Vet (A : in out Animal_T) is abstract;

end Animal;
然后,您的简单过程中的类型定义需要进行相应的调整(这里我只是使用了Animal软件包来保持简单):

汇编:

[17] Marc say: gnatmake -gnat05 simple
gcc -c -gnat05 simple.adb
gcc -c -gnat05 animal.ads
gnatbind -x simple.ali
gnatlink simple.ali
最后:

[18] Marc say: ./simple
Cat
如何将母牛分配给Aa?(Aa:=一头牛;抱怨!)

你不能也不应该。尽管它们共享一个共同的基类,但它们是两种不同的类型。与Java相比,尝试将cat转换为cow会在运行时导致
ClassCastException
。Ada在编译时排除了这个问题,就像Java泛型声明一样

我已经扩展了@Marc的示例,展示了如何调用基类子程序。请注意在
过程简单中使用的

增编:正如你所提到的,我应该补充与下面的例子有关的几点。特别是类范围内的操作,例如
Get\u Weight
Set\u Weight
,是可用的,但是。此外,这些子程序相当做作,因为标记的记录组件可以直接访问,例如
Tabby.Weight

package Animal is

   type Animal_T is abstract tagged record
      Weight : Integer := 0;
   end record;

   procedure Go_To_Vet (A : in out Animal_T) is abstract;
   function  Get_Weight (A : in Animal_T'Class) return Natural;
   procedure Set_Weight (A : in out Animal_T'Class; W : in Natural);

end Animal;

package body Animal is

   function Get_Weight (A : in Animal_T'Class) return Natural is
   begin
      return A.Weight;
   end Get_Weight;

   procedure Set_Weight (A : in out Animal_T'Class; W : in Natural) is
   begin
      A.Weight := W;
   end Set_Weight;

end Animal;

with Ada.Text_IO; use Ada.Text_IO;
with Animal; use Animal;
procedure Simple is

   type Cat_T is new Animal_T with record
      Fur : Boolean;
   end record;

   procedure Go_To_Vet (A : in out Cat_T)
   is
   begin
      Ada.Text_Io.Put_Line ("Cat");
   end Go_To_Vet;

   type Cow_T is new Animal_T with record
      Dairy : Boolean;
   end record;

   procedure Go_To_Vet (A : in out Cow_T) is
   begin
      Ada.Text_Io.Put_Line ("Cow");
   end Go_To_Vet;

   A_Cat : Cat_T := (Weight => 5, Fur => True);
   A_Cow : Cow_T := (Weight => 200, Dairy => False);
   Tabby : Animal_T'Class := A_Cat;
   Bossy : Animal_T'Class := A_Cow;

begin
   Go_To_Vet (Tabby);
   Put_Line (Tabby.Get_Weight'Img);
   Go_To_Vet (Bossy);
   Put_Line (Bossy.Get_Weight'Img);
   -- feed Bossy
   Bossy.Set_Weight (210);
   Put_Line (Bossy.Get_Weight'Img);
end Simple;

谢谢,马克,我就知道是这样的!我的次要问题是如何将一头母牛分配给aa?(aa:=一头母牛;抱怨!)+1个好例子@NWS:作业是被禁止的,正如在邻近的一篇文章中所讨论的。感谢垃圾,我认为作业是可能的,但通过类范围的指针解决了这个问题:)这可能是我一直在想的……有趣的是,对于两个具体的
Go_To_Vet
过程,你可以不用子程序规范就可以逃脱。但是,您必须将主体放在类型声明之后。@Simon Wright:它只适用于第一个子程序;第二个选项会产生“重写名称太晚了。”令人高兴的是,错误消息是“spec应该在类型之后立即出现。”@NWS:我很欣赏这个复选标记,但是@Marc的答案在我之前。如果你改变主意,我很乐意听从他。当然,你也可以对任何你觉得有用的答案投赞成票。:-)感谢您的宽宏大量(这是一个很好的阐述:-),您可以通过使变量aa成为类范围类型的访问权限来完成赋值;但是,有一些限制需要记住:1)您不能将不同类别的项目直接分配给该项目,必须使用新的;2) 如果出于某种原因,您试图动态构造一个类范围的变量[非访问](比如从文件或键盘),那么您可能应该实例化泛型构造函数,请参阅:@Shark8:谢谢。我忍不住注意到它与我的相似之处。
[18] Marc say: ./simple
Cat
package Animal is

   type Animal_T is abstract tagged record
      Weight : Integer := 0;
   end record;

   procedure Go_To_Vet (A : in out Animal_T) is abstract;
   function  Get_Weight (A : in Animal_T'Class) return Natural;
   procedure Set_Weight (A : in out Animal_T'Class; W : in Natural);

end Animal;

package body Animal is

   function Get_Weight (A : in Animal_T'Class) return Natural is
   begin
      return A.Weight;
   end Get_Weight;

   procedure Set_Weight (A : in out Animal_T'Class; W : in Natural) is
   begin
      A.Weight := W;
   end Set_Weight;

end Animal;

with Ada.Text_IO; use Ada.Text_IO;
with Animal; use Animal;
procedure Simple is

   type Cat_T is new Animal_T with record
      Fur : Boolean;
   end record;

   procedure Go_To_Vet (A : in out Cat_T)
   is
   begin
      Ada.Text_Io.Put_Line ("Cat");
   end Go_To_Vet;

   type Cow_T is new Animal_T with record
      Dairy : Boolean;
   end record;

   procedure Go_To_Vet (A : in out Cow_T) is
   begin
      Ada.Text_Io.Put_Line ("Cow");
   end Go_To_Vet;

   A_Cat : Cat_T := (Weight => 5, Fur => True);
   A_Cow : Cow_T := (Weight => 200, Dairy => False);
   Tabby : Animal_T'Class := A_Cat;
   Bossy : Animal_T'Class := A_Cow;

begin
   Go_To_Vet (Tabby);
   Put_Line (Tabby.Get_Weight'Img);
   Go_To_Vet (Bossy);
   Put_Line (Bossy.Get_Weight'Img);
   -- feed Bossy
   Bossy.Set_Weight (210);
   Put_Line (Bossy.Get_Weight'Img);
end Simple;