使用基本操作创建对象

时间:2019-03-26 18:38:02

标签: ada

我的问题包含一段较长的Ada代码。基本上,我尝试以面向对象的方式为带有标题的消息建模。两个基本操作Create_MessageCreate_Message_Access可用于创建具体的消息对象。我不确定原始操作是否应返回类型Message_TypeMessage_Type_Access。建议使用哪种类型(效率?)还是两种解决方案都不都是最佳选择?

我认为,第一种方法是在堆栈上创建对象,然后在执行return语句后将其复制,因为变量Object超出范围。对还是错?

function Create_Message (Title : String) return Message_Type is
   Object : Message_Type;
begin
   Object.Title := To_Unbounded_String (Title);

   return Object;
end Create_Message;

我认为,第二种方法是在堆上创建对象,然后在执行return语句后复制 pointer ,因为变量Object不再存在范围。对还是错?

function Create_Message_Access (Title : String) return Message_Type_Access is
   Object : Message_Type_Access := new Message_Type;
begin
   Object.Title := To_Unbounded_String (Title);

   return Object;
end Create_Message_Access;

稍后,我创建了一个带有标题的示例对象,使用原始操作Updated_Title更改了标题并将其更改回末尾。

First_Message := Message.Create_Message ("First");

Ada.Text_IO.Put_Line (First_Message.Get_Title);

First_Message.Update_Title ("First changed");

Ada.Text_IO.Put_Line (First_Message.Get_Title);

First_Message.Update_Title ("First");

Ada.Text_IO.Put_Line (First_Message.Get_Title); 

输出为(预期):

First
First changed
First

然后,我将消息保存在矢量容器中,并尝试在遍历矢量中存储的元素的同时更改标题。我发现标题保留了旧值,因此我假设调用操作Message_Vector.Element (Message_Cursor)仅返回存储在向量中的消息的副本。对还是错?

Messages.Append (First_Message);

Message_Cursor := Message_Vector.First (Messages);

while Message_Vector.Has_Element (Message_Cursor) loop
   declare
      Temporary_Message : Message.Message_Type;
   begin
      Temporary_Message := Message_Vector.Element (Message_Cursor);
      Temporary_Message.Update_Title ("First changed");
   end;

   Message_Vector.Next (Message_Cursor);
end loop;

Message_Cursor := Message_Vector.First (Messages);

while Message_Vector.Has_Element (Message_Cursor) loop
   --
   -- Prints "First" and not "First changed"
   --
   Ada.Text_IO.Put_Line (Message_Vector.Element (Message_Cursor).Get_Title);

   Message_Vector.Next (Message_Cursor);
end loop;

最后一个问题:Second_Message.all.Get_TitleSecond_Message.Get_Title有什么区别?

Second_Message := Message.Create_Message_Access ("Second");

Ada.Text_IO.Put_Line (Second_Message.all.Get_Title);
Ada.Text_IO.Put_Line (Second_Message.Get_Title);

完整源代码:

with Ada.Containers.Vectors;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;

with Ada.Text_IO;

procedure Main is

   package Message is

      type Message_Type is tagged private;

      type Message_Type_Access is access Message_Type;

      function Create_Message (Title : String) return Message_Type;

      function Create_Message_Access (Title : String) return Message_Type_Access;

      function Get_Title (Self : Message_Type) return String;

      procedure Update_Title (Self : in out Message_Type; Title : String);

      function "=" (Left, Right : Message_Type) return Boolean;

   private

      type Message_Type is tagged record
         Title : Unbounded_String;
      end record;

   end Message;

   package body Message is

      function Create_Message (Title : String) return Message_Type is
         Object : Message_Type;
      begin
         Object.Title := To_Unbounded_String (Title);

         return Object;
      end Create_Message;

      function Create_Message_Access (Title : String) return Message_Type_Access is
         Object : Message_Type_Access := new Message_Type;
      begin
         Object.Title := To_Unbounded_String (Title);

         return Object;
      end Create_Message_Access;

      function Get_Title (Self : Message_Type) return String is
      begin
         return To_String (Self.Title);
      end Get_Title;

      procedure Update_Title (Self : in out Message_Type; Title : String) is
      begin
         Self.Title := To_Unbounded_String (Title);
      end Update_Title;

      function "=" (Left, Right : Message_Type) return Boolean is
      begin
         return Left.Title = Right.Title;
      end "=";

   end Message;

   package Message_Vector is new Ada.Containers.Vectors (Index_Type => Natural,
      Element_Type => Message.Message_Type, "=" => Message."=");

   package Message_Access_Vector is new Ada.Containers.Vectors (Index_Type => Natural,
      Element_Type => Message.Message_Type_Access, "=" => Message."=");

   Messages       : Message_Vector.Vector;
   Message_Cursor : Message_Vector.Cursor;

   Messages_Access       : Message_Access_Vector.Vector;
   Message_Access_Cursor : Message_Access_Vector.Cursor;

   First_Message  : Message.Message_Type;
   Second_Message : Message.Message_Type_Access;

begin
   First_Message := Message.Create_Message ("First");

   Ada.Text_IO.Put_Line (First_Message.Get_Title);

   First_Message.Update_Title ("First changed");

   Ada.Text_IO.Put_Line (First_Message.Get_Title);

   First_Message.Update_Title ("First");

   Ada.Text_IO.Put_Line (First_Message.Get_Title);

   --

   Ada.Text_IO.New_Line;

   Messages.Append (First_Message);

   Message_Cursor := Message_Vector.First (Messages);

   while Message_Vector.Has_Element (Message_Cursor) loop
      declare
         Temporary_Message : Message.Message_Type;
      begin
         Temporary_Message := Message_Vector.Element (Message_Cursor);
         Temporary_Message.Update_Title ("First changed");
      end;

      Message_Vector.Next (Message_Cursor);
   end loop;

   Message_Cursor := Message_Vector.First (Messages);

   while Message_Vector.Has_Element (Message_Cursor) loop
      --
      -- Prints "First" and not "First changed"
      --
      Ada.Text_IO.Put_Line (Message_Vector.Element (Message_Cursor).Get_Title);

      Message_Vector.Next (Message_Cursor);
   end loop;

   --

   Ada.Text_IO.New_Line;

   Second_Message := Message.Create_Message_Access ("Second");

   Ada.Text_IO.Put_Line (Second_Message.all.Get_Title);
   Ada.Text_IO.Put_Line (Second_Message.Get_Title);

   --

   Ada.Text_IO.New_Line;

   Messages_Access.Append (Second_Message);

   Message_Access_Cursor := Message_Access_Vector.First (Messages_Access);

   while Message_Access_Vector.Has_Element (Message_Access_Cursor) loop
      declare
         Temporary_Message : Message.Message_Type_Access;
      begin
         Temporary_Message := Message_Access_Vector.Element (Message_Access_Cursor);
         Temporary_Message.Update_Title ("Second changed");
      end;

      Message_Access_Vector.Next (Message_Access_Cursor);
   end loop;

   Message_Access_Cursor := Message_Access_Vector.First (Messages_Access);

   while Message_Access_Vector.Has_Element (Message_Access_Cursor) loop
      Ada.Text_IO.Put_Line (Message_Access_Vector.Element (Message_Access_Cursor).Get_Title);

      Message_Access_Vector.Next (Message_Access_Cursor);
   end loop;

end Main;

1 个答案:

答案 0 :(得分:5)

  

两个基本操作Create_Message和Create_Message_Access可用于创建具体的消息对象。我不确定原始操作是否应返回Message_Type或Message_Type_Access类型。建议使用哪种类型(效率?)还是两种解决方案都不都是最佳选择?

哪个最好取决于情况。通常,最好避免使用指针,但是,如果要表示的对象是系统中具有永久性的对象,则只需拥有一个副本即可。我已经限制了它们,并使用了指针容器。

  

我认为第一种方法是在堆栈上创建对象,然后在执行return语句后将其复制,因为变量Object超出范围。对还是错?

我认为它会在return语句中复制,但除此之外,是的(在某些情况下,您可以“就地构建对象”涉及有限的类型,但是在语言标准版本之间,规则有所变化,因此我不确定;请参阅AARM 7.6(17.1)并准备为之困惑)。

  

我认为第二种方法是在堆上创建对象,然后在执行return语句后复制指针,因为变量Object超出范围。对还是错?

再次,是。

  

...我假设调用操作Message_Vector.Element(Message_Cursor)仅返回存储在向量中的消息的副本。对还是错?

是的

  

最后一个问题:Second_Message.all.Get_Title和Second_Message.Get_Title有什么区别?

在这种情况下,没有。但是,如果过程没有参数,则需要使用第一种形式,因为它显然不是子程序调用。


类似Element的操作确实会返回一个副本。如果要更新容器中的元素,则可以复制,修改它,然后使用Replace_Element覆盖原始元素。

您可能会发现使用Update_Element的麻烦(但仅仅是):

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Vectors;
procedure Updating_Messages is
   type Message is record
      N : Integer := 0;
   end record;
   package Message_Vectors is
     new Ada.Containers.Vectors (Index_Type => Positive,
                                 Element_Type => Message);
   Messages : Message_Vectors.Vector;
begin
   Messages.Append (Message'(N => 21));                                     -- sorry about this, failing of Google syntax highlighting '
   Messages.Append (Message'(N => 42));                                     --'
   for Cursor in Messages.Iterate loop
      declare
         procedure Increment (It : in out Message) is
         begin
            It.N := It.N + 1;
         end Increment;
      begin
         Messages.Update_Element (Cursor, Increment'Access);                --'
      end;
   end loop;
   for M of Messages loop  -- these are copies
      Ada.Text_IO.Put_Line (M.N'Image);                                     --'
   end loop;
end Updating_Messages;