【问题标题】:Dynamic Dispatching in Ada with Access Types具有访问类型的 Ada 中的动态调度
【发布时间】:2016-03-11 06:00:05
【问题描述】:

我正在尝试创建一个使用访问类型进行动态调度的包。我以This Q/A 为指导,使用类类型实现了动态调度。

我不断收到一个编译错误:无法调用抽象子程序。这让我觉得编译器要么不识别专门的子程序,要么不将类型识别为专门的类型。但在我看来,两者都是正确的……我不明白。

ma​​in.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;

错误

main.2.ada:13:21:无法调用抽象子程序“Is_Happy”

【问题讨论】:

  • 您为什么使用访问类型以及动态调度?如果您只尝试动态调度,这可能会更容易。
  • @JacobSparreAndersen - 我使用访问类型是因为在我的实际代码中,我使用的是相当大的对象,这不是我可以改变的事实。我宁愿明确地使用指针,也不愿希望优化器为我这样做。我以为我在我的方法Stroke_Fur 中使用了动态调度,并且它起作用了。你能澄清你为什么问这个问题吗?听起来你在推断两者应该是互斥的,但我不太确定你的意思。
  • 大多数 Ada 程序员已经开始依赖他们的编译器供应商来避免生成效率极低的代码。参数模式表示意图;对于access,您不太确定传递的对象会发生什么。无论如何,标记的类型都是通过引用 (AARM05 6.2)。
  • @Jerunh 我问是因为使用访问类型是一种不必要的复杂性,它可能会隐藏您对标记类型的实际挑战。 (正如 Simon 所写,标记类型是按引用传递的类型,因此优化器对它们如何作为参数传递没有任何发言权。)

标签: dynamic polymorphism ada


【解决方案1】:
function Is_Happy (Ptr : in Any_Animal_Ptr) return boolean is abstract;

不是Animal_t 的原始操作(ARM3.2.3(2)),因此它不是调度;它只是一个抽象的子程序(因此不能被调用)。

为什么要制作非调度子程序摘要?也许您可能有一个 Metres 类型,在这种情况下,预定义的 ”*” 是不合适的(以米为单位的两个距离相乘返回一个区域,而不是一个距离),您可能希望将其抽象化以防止无意误用。

无论如何,您可以使用访问 as 声明 Animal_t 的原始操作

function Is_Happy (Ptr : access Animal_t) return boolean is abstract;

然后是猫

function Is_Happy (Ptr : access Cat_t) return Boolean;

(甚至

overriding
function Is_Happy (Ptr : access Cat_t) return Boolean;

如果您希望编译器检查它是否真的被覆盖)。

顺便说一句,如果您使用的是 Ada 2005 或更高版本,您可以使用 prefixed notation 将调用编写为

Animal_Ref.Stroke_Fur;
Result := Animal_Ref.Is_Happy;

哪个更漂亮。

【讨论】:

  • 谢谢。我的方法是抽象的,因为它对默认实现没有意义。显然,这只是我写的一个简单的例子来分享。我相信大多数 Ada 程序员可能出于以下几个原因之一无法分享他们的实际代码。加上 10 次中的 9 次,当我创建一个简化的示例来分享时,我通常会解决我自己的问题。再次感谢,这很有帮助并解决了我的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-18
相关资源
最近更新 更多