Class 我怎样才能让这个调度电话开始工作?
我试图熟悉Ada中的面向对象。几个月前,你的网站帮助我解决了另一个O-O问题,我希望你愿意再次提供帮助 情况:我有一个抽象类型“token”和两个派生类型“otoken”和“vtoken”。我想把这两个派生类型放在同一个数组中,并让它们正确地分派 我的教科书建议将数组声明为包含指向token'class的指针,这迫使我在整个过程中遍历点。下面是我的程序的精简版本,但它不会编译,因为编译器说我的分派调用“不明确”Class 我怎样才能让这个调度电话开始工作?,class,oop,ada,tag-dispatching,Class,Oop,Ada,Tag Dispatching,我试图熟悉Ada中的面向对象。几个月前,你的网站帮助我解决了另一个O-O问题,我希望你愿意再次提供帮助 情况:我有一个抽象类型“token”和两个派生类型“otoken”和“vtoken”。我想把这两个派生类型放在同一个数组中,并让它们正确地分派 我的教科书建议将数组声明为包含指向token'class的指针,这迫使我在整个过程中遍历点。下面是我的程序的精简版本,但它不会编译,因为编译器说我的分派调用“不明确” ------------------------------------------
---------------------------------------------------------------------------------
--------------------------------------------
-- Tokensamp.ads
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Command_Line; use Ada.Command_Line;
package tokensamp is
type token is abstract tagged record
x: integer;
end record;
type otoken is new token with record
y: integer;
end record;
type vtoken is new token with record
z: integer;
end record;
type potoken is access otoken;
type pvtoken is access vtoken;
end tokensamp;
------------------------------------------------------------------------------------------------------
-- Parsesamp.ads:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Command_Line; use Ada.Command_Line;
with tokensamp;
package parsesamp is
function rootOfTree( t: tokensamp.pvtoken) return integer;
function rootOfTree( t: tokensamp.potoken) return integer;
end parsesamp;
-------------------------------------------
-- parsesamp.adb:
package body parsesamp is
function rootOfTree( t: tokensamp.pvtoken) return integer is
begin
return t.z * 2;
end rootOfTree;
function rootOfTree( t: tokensamp.potoken) return integer is
begin
return t.y * 2;
end rootOfTree;
result: integer;
type tarray is array (1..2) of access tokensamp.token'class ;
tl: tarray;
begin
for i in 1..2 loop
result := rootOfTree( tl(i) );
end loop;
end parsesamp;
-------------------------------------------------------------
当我使用GNAT Ada 95编译器编译此文件时,会收到错误消息:
C:\GNAT\2018\bin\ceblang>gnatmake parsesamp.adb
gcc -c parsesamp.adb
parsesamp.adb:25:27: ambiguous expression (cannot resolve "rootOfTree")
parsesamp.adb:25:27: possible interpretation at parsesamp.ads:9
parsesamp.adb:25:27: possible interpretation at parsesamp.ads:8
gnatmake: "parsesamp.adb" compilation error
换句话说,它无法将这两个函数识别为备用调度调用。如果您能给我一些建议,我将不胜感激,因为我已经在这方面纠缠了好几天。您的困惑似乎包括包的使用和Ada中调度操作的定义方式。 调度操作必须在定义标记数据类型的同一包中定义,但在定义任何其他类型之前
package Tokens is
type token is tagged private;
function Root_Of_Tree(T : Token) return Integer;
type Token_Access is access all Token'Class;
type Token_Array is array (Positive range <>) of Token_Access;
private
type Token is tagged record
X : Integer := 1;
end record;
end Tokens;
我使用了子包来定义Otoken和Vtoken类型
package Tokens.OTokens is
type Otoken is new Token with private;
function Root_Of_Tree(T : Otoken) return Integer;
private
type Otoken is new Token with record
Y : Integer := 2;
end record;
end Tokens.OTokens;
Tokens.OTokens的主体是:
package body Tokens.OTokens is
------------------
-- Root_Of_Tree --
------------------
function Root_Of_Tree (T : Otoken) return Integer is
begin
return T.Y * 2;
end Root_Of_Tree;
end Tokens.OTokens;
package tokens.vtokens is
type vtoken is new token with private;
function Root_Of_Tree(T : vtoken) return Integer;
private
type vtoken is new token with record
Z : Integer := 3;
end record;
end tokens.vtokens;
Tokens.VTokens的规范为:
package body Tokens.OTokens is
------------------
-- Root_Of_Tree --
------------------
function Root_Of_Tree (T : Otoken) return Integer is
begin
return T.Y * 2;
end Root_Of_Tree;
end Tokens.OTokens;
package tokens.vtokens is
type vtoken is new token with private;
function Root_Of_Tree(T : vtoken) return Integer;
private
type vtoken is new token with record
Z : Integer := 3;
end record;
end tokens.vtokens;
正文标记。Vtokens是:
package body tokens.vtokens is
------------------
-- Root_Of_Tree --
------------------
function Root_Of_Tree (T : vtoken) return Integer is
begin
return T.Z * 2;
end Root_Of_Tree;
end tokens.vtokens;
创建包含一个otoken和一个vtoken的数组的主要过程如下:
with Ada.Text_IO; use Ada.Text_Io;
with Tokens; use Tokens;
with Tokens.OTokens; use Tokens.OTokens;
with tokens.vtokens; use tokens.vtokens;
procedure Main is
Ot : token_Access := new Otoken;
Vt : token_access := new vtoken;
Ta : Token_Array := (Ot, Vt);
begin
for tk of Ta loop
Put_Line(Integer'Image(Root_of_Tree(tk.all)));
end loop;
end Main;
最好记住,OToken类型包含两个字段X和Y。VToken类型包含两个字段X和Z。
主程序的输出为:
4
6
您的困惑似乎包括包的使用和Ada中定义分派操作的方式。 调度操作必须在定义标记数据类型的同一包中定义,但在定义任何其他类型之前
package Tokens is
type token is tagged private;
function Root_Of_Tree(T : Token) return Integer;
type Token_Access is access all Token'Class;
type Token_Array is array (Positive range <>) of Token_Access;
private
type Token is tagged record
X : Integer := 1;
end record;
end Tokens;
我使用了子包来定义Otoken和Vtoken类型
package Tokens.OTokens is
type Otoken is new Token with private;
function Root_Of_Tree(T : Otoken) return Integer;
private
type Otoken is new Token with record
Y : Integer := 2;
end record;
end Tokens.OTokens;
Tokens.OTokens的主体是:
package body Tokens.OTokens is
------------------
-- Root_Of_Tree --
------------------
function Root_Of_Tree (T : Otoken) return Integer is
begin
return T.Y * 2;
end Root_Of_Tree;
end Tokens.OTokens;
package tokens.vtokens is
type vtoken is new token with private;
function Root_Of_Tree(T : vtoken) return Integer;
private
type vtoken is new token with record
Z : Integer := 3;
end record;
end tokens.vtokens;
Tokens.VTokens的规范为:
package body Tokens.OTokens is
------------------
-- Root_Of_Tree --
------------------
function Root_Of_Tree (T : Otoken) return Integer is
begin
return T.Y * 2;
end Root_Of_Tree;
end Tokens.OTokens;
package tokens.vtokens is
type vtoken is new token with private;
function Root_Of_Tree(T : vtoken) return Integer;
private
type vtoken is new token with record
Z : Integer := 3;
end record;
end tokens.vtokens;
正文标记。Vtokens是:
package body tokens.vtokens is
------------------
-- Root_Of_Tree --
------------------
function Root_Of_Tree (T : vtoken) return Integer is
begin
return T.Z * 2;
end Root_Of_Tree;
end tokens.vtokens;
创建包含一个otoken和一个vtoken的数组的主要过程如下:
with Ada.Text_IO; use Ada.Text_Io;
with Tokens; use Tokens;
with Tokens.OTokens; use Tokens.OTokens;
with tokens.vtokens; use tokens.vtokens;
procedure Main is
Ot : token_Access := new Otoken;
Vt : token_access := new vtoken;
Ta : Token_Array := (Ot, Vt);
begin
for tk of Ta loop
Put_Line(Integer'Image(Root_of_Tree(tk.all)));
end loop;
end Main;
最好记住,OToken类型包含两个字段X和Y。VToken类型包含两个字段X和Z。
主程序的输出为:
4
6
首先,您需要将
rootOfTree
声明为抽象操作
令牌的:
type token is abstract tagged record
x: integer;
end record;
function rootOfTree( t: tokensamp.token) return Integer is abstract;
(必须在启用标记之前声明基本操作
冷冻,基本上是在使用它之前,比如在声明中
派生类型)
然后声明otoken
和vtoken
的基本操作;他们
必须在与其对应的类型相同的包中声明
是原始的,即可以分派给
type otoken is new token with record
y: integer;
end record;
type vtoken is new token with record
z: integer;
end record;
function rootOfTree( t: tokensamp.vtoken) return integer;
function rootOfTree( t: tokensamp.otoken) return integer;
(更正常的做法是在每个参数之后立即声明它们
键入,但由于两者都不冻结另一个,因此这是可以的)
请注意,rootOfTree
操作都不是访问类型
参数
你不需要<代码> PoToMe</代码>,<代码> PVTu饰>代码>,尽管你可以考虑
在此处声明类范围指针:
type ptoken is access token'class;
然后,您需要为包tokensamp
声明一个主体,其中包含
两个具体的rootOfTree
s的实现
考虑到parsesamp
,您不能在这里声明rootOfTree
你可以写
result := tokensamp.rootOfTree (t1(i).all);
(t1(i)
是指向类范围的指针,。all
是类范围的值,并且
tokensamp.rootOfTree
是一个可调度的操作,因此这是一个
调度电话)
。。或者你可以用更漂亮的速记法
result := t1(i).rootOfTree;
首先,您需要将rootOfTree
声明为抽象操作
令牌的
:
type token is abstract tagged record
x: integer;
end record;
function rootOfTree( t: tokensamp.token) return Integer is abstract;
(必须在启用标记之前声明基本操作
冷冻,基本上是在使用它之前,比如在声明中
派生类型)
然后声明otoken
和vtoken
的基本操作;他们
必须在与其对应的类型相同的包中声明
是原始的,即可以分派给
type otoken is new token with record
y: integer;
end record;
type vtoken is new token with record
z: integer;
end record;
function rootOfTree( t: tokensamp.vtoken) return integer;
function rootOfTree( t: tokensamp.otoken) return integer;
(更正常的做法是在每个参数之后立即声明它们
键入,但由于两者都不冻结另一个,因此这是可以的)
请注意,rootOfTree
操作都不是访问类型
参数
你不需要<代码> PoToMe</代码>,<代码> PVTu饰>代码>,尽管你可以考虑
在此处声明类范围指针:
type ptoken is access token'class;
然后,您需要为包tokensamp
声明一个主体,其中包含
两个具体的rootOfTree
s的实现
考虑到parsesamp
,您不能在这里声明rootOfTree
你可以写
result := tokensamp.rootOfTree (t1(i).all);
(t1(i)
是指向类范围的指针,。all
是类范围的值,并且
tokensamp.rootOfTree
是一个可调度的操作,因此这是一个
调度电话)
。。或者你可以用更漂亮的速记法
result := t1(i).rootOfTree;
作为Jim Rogers和Simon Wright给出的答案的补充,如果你使用艾达2012,那么你可以考虑使用不定的持有者来构造你的数组(参见和
)。
如基本原理中所述,持有者是可以容纳(和管理)对象的单个实例的容器。当对象作为参数传递给to_Holder
子程序(参见下面的示例)时,该对象被复制到堆实例中,而堆实例在不再需要时(例如,当它被替换或当Holder超出范围时)会被销毁。因此,holder容器使您不再像直接使用access
类型时那样手动管理内存
(性能)成本是复制传递给to_Holder
程序的对象。您可以在保持器之间“移动”对象(使用th中定义的move
子程序)