我有一个基本类型,其工作是维护项目列表。它具有非调度功能,可以向其中添加项目以及从中检索项目列表。
从此基本类型派生的类型使用某些调度子程序中的项目。我已经可以通过使基本类型包含项的向量来实现这一点,但是如果可能的话,我希望数组是静态的。这是我到目前为止的内容:
bases.ads:
package Bases is
type Base (<>) is tagged private; -- I want to hide the size
type Int_List is array (Positive range <>) of Integer; -- as an example
function Create return Base; -- returns an empty Base
function Add_To (This : Base'Class; I : Integer) return Base'Class; -- Append
function Image (This : Base) return String; -- Dispatching example
function List (This : Base'Class) return Int_List; -- Get the data for internal use
private
type Base (Size : Natural) is tagged record
Ints : Int_List (1 .. Size);
end record;
end Bases;
bases.adb:
package body Bases is
function Create return Base is (Size => 0, Ints => (others => 0));
function Add_To (This : Base'Class; I : Integer) return Base'Class is
-- This is where I have trouble: "aggregate cannot be of a class-wide type"
Copy : Base'Class := (This with Size => This.Size + 1, Ints => This.Ints & I);
begin
return Copy;
end Add_To;
function Image (This : Base) return String is ("BASE");
function List (This : Base'Class) return Int_List is (This.Ints);
end Bases;
deriveds.ads:
with Bases;
package Deriveds is
type Derived is new Bases.Base with null record;
function Create return Derived;
function Image (This : Derived) return String;
end Deriveds;
deriveds.adb:
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
package body Deriveds is
function Create return Derived is (Bases.Create with null record);
function Image (This : Derived) return String is
Result : Unbounded_String;
Ints : Bases.Int_List := This.List;
begin
for I in Ints'Range loop
Result := Result & Integer'Image (Ints (I));
end loop;
return To_String (Result);
end Image;
end Deriveds;
同样,我知道如果我只是删除判别式并使用受控类型来存储数组,那么我可以将副本创建为Copy : Base'Class := This;
并对其进行变异,然后再返回它。但是,我觉得应该只有静态内存才可以做到这一点,这是可取的。我唯一想到的其他解决方法是创建另一个标记类型,该类型将是包含列表和Base'Class
数据的记录,并且其操作将遮盖Base
调度操作,使其通过。
是否无法在Copy
中创建Add_To
,使其判别式大1,并且仅使用静态内存就具有额外的元素?
答案 0 :(得分:1)
我认为麻烦在于Bases.Add_To
没有一种愉快的标准方法来知道要追加到Base
记录(递增Size
)以复制特定于类的实际数据的内容在This
中。
我想您可以不受限制地转换并通过使用Ada.Tags.Generic_Dispatching_Constructor
(here,here)来构建记录;但这似乎是个坏主意。
答案 1 :(得分:1)
我知道这需要更多的工作,但是您也可以将Add_To更改为使用Base而不是Base'Class。然后,您必须为具有大于null记录扩展名的所有派生类型重写它,但是您将获得所需的静态数组结果。派生的实现将类似于您实现Create的方式。
示例(我将派生类修改为具有非null记录扩展名,以强制 编译器要求您派生该操作:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
procedure Hello is
package Bases is
type Base (<>) is tagged private; -- I want to hide the size
type Int_List is array (Positive range <>) of Integer; -- as an example
function Create return Base; -- returns an empty Base
function Add_To (This : Base; I : Integer) return Base; -- Append
function Image (This : Base) return String; -- Dispatching example
function List (This : Base'Class) return Int_List; -- Get the data for internal use
private
type Base (Size : Natural) is tagged record
Ints : Int_List (1 .. Size);
end record;
end Bases;
package body Bases is
function Create return Base is (Size => 0, Ints => (others => 0));
function Add_To (This : Base; I : Integer) return Base is
-- This is where I have trouble: "aggregate cannot be of a class-wide type"
Copy : Base := (Size => This.Size + 1, Ints => This.Ints & I);
begin
return Copy;
end Add_To;
function Image (This : Base) return String is ("BASE");
function List (This : Base'Class) return Int_List is (This.Ints);
end Bases;
package Deriveds is
type Derived is new Bases.Base with record
Value : Integer;
end record;
function Create return Derived;
function Add_To(This : Derived; I : Integer) return Derived;
function Image (This : Derived) return String;
end Deriveds;
package body Deriveds is
function Create return Derived is (Bases.Create with Value => 0);
function Image (This : Derived) return String is
Result : Unbounded_String;
Ints : Bases.Int_List := This.List;
begin
for I in Ints'Range loop
Result := Result & Integer'Image (Ints (I));
end loop;
return To_String (Result);
end Image;
function Add_To(This : Derived; I : Integer) return Derived is
begin
return (Bases.Base(This).Add_To(I) with Value => This.Value);
end Add_To;
end Deriveds;
use Deriveds;
d0 : Derived := Create;
d1 : Derived := d0.Add_To(1).Add_To(3);
d2 : Derived := d1.Add_To(2);
begin
Put_Line(d2.Image);
end Hello;