问题
I am trying to create a package that has Dynamic dispatching using access types. I have achieved Dynamic Dispatching using Class Types using This Q/A as a guide.
I keep getting a compilation error that says: cannot call abstract subprogram. This makes me think that the compiler either doesnt recognize the specialized subprogram, or doesnt recognize the type as a specialized type. But both seem right to me... I dont get it.
main.2.ada
with Ada.Text_IO;
with Animal.Cat;
procedure Main is
Tabby : aliased Animal.Cat.Cat_t;
Animal_Ref : Animal.Any_Animal_Ptr := Tabby'Unchecked_Access;
Result : Boolean;
begin
Animal.Stroke_Fur (Animal => Animal_Ref.all);
Result := Animal.Is_Happy(Ptr => Animal_Ref);
Ada.Text_IO.Put_Line ("Happy Animal = " & Boolean'Image (Result));
end Main;
animal.1.ada
package Animal is
type base_t is abstract tagged limited null record;
type Animal_t is abstract new
base_t with private;
type Any_Animal_Ptr is access all Animal_t'Class;
----
procedure Stroke_Fur (Animal : in out Animal_t) is abstract;
----
function Is_Happy (Ptr : in Any_Animal_Ptr) return boolean is abstract;
private
type Animal_t is abstract new base_t with
record
Index : integer;
end record;
end Animal;
animal.cat.1.ada
package Animal.Cat is
type Cat_t is new Animal.Animal_t with private;
type Cat_Ptr is access all Cat_t;
----
procedure Stroke_Fur (Cat : in out Cat_t);
----
function Is_Happy (Ptr : in Cat_Ptr) return Boolean;
private
type Cat_t is new Animal.Animal_t with
record
Purr : Boolean := False;
end record;
end Animal.Cat;
animal.cat.2.ada
package body Animal.Cat is
----
procedure Stroke_Fur (Cat : in out Cat_t) is
begin
Cat.Purr := True;
end Stroke_Fur;
----
function Is_Happy (Ptr : in Cat_Ptr) return Boolean is
begin
return Ptr.Purr;
end Is_Happy;
end Animal.Cat;
Error
main.2.ada:13:21: cannot call abstract subprogram "Is_Happy"
回答1:
function Is_Happy (Ptr : in Any_Animal_Ptr) return boolean is abstract;
isn’t a primitive operation (ARM3.2.3(2)) of Animal_t
, and so it isn’t dispatching; it’s merely an abstract subprogram (which therefore can’t be called).
Why would you want to make a non-dispatching subprogram abstract? Perhaps you might have a type Metres
, in which case the predefined ”*”
is inappropriate (multiplying two distances in metres returns an area, not a distance) and you might want to make it abstract to prevent inadvertent misuse.
Anyway, you can declare a primitive operation of Animal_t
using accesses as
function Is_Happy (Ptr : access Animal_t) return boolean is abstract;
and then for cats
function Is_Happy (Ptr : access Cat_t) return Boolean;
(or even
overriding
function Is_Happy (Ptr : access Cat_t) return Boolean;
if you want the compiler to check that it really is overriding).
By the way, if you are using Ada 2005 or later you can use the prefixed notation to write the calls as
Animal_Ref.Stroke_Fur;
Result := Animal_Ref.Is_Happy;
which is prettier.
来源:https://stackoverflow.com/questions/35898525/dynamic-dispatching-in-ada-with-access-types