代码之家  ›  专栏  ›  技术社区  ›  LambdaBeta

如何通过修改Ada中的基类型返回类范围对象的副本

  •  0
  • LambdaBeta  · 技术社区  · 6 年前

    我有一个基本类型,它的工作是维护项目列表。它有一个非调度函数,可以向其中添加项目,也可以从中检索项目列表。

    基地.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;
    

    基础.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;
    

    衍生广告:

    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

    2 回复  |  直到 6 年前
        1
  •  2
  •   Jere    6 年前

    示例(我修改了派生类,使其具有要强制的非空记录扩展

    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;
    
        2
  •  1
  •   Simon Wright    6 年前

    Bases.Add_To 没有令人愉快的,标准的方式来知道什么附加到 Base 记录(带 Size 增量)以复制中的实际类特定数据 This

    我想你可以在未经检查的转换中混日子&也许可以使用, Ada.Tags.Generic_Dispatching_Constructor ( here , here );但这似乎是个坏主意。