使用基本操作创建对象

Mar*_*o90 2 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;
Run Code Online (Sandbox Code Playgroud)

我认为第二种方法是在堆上创建对象,然后在执行语句后复制指针,return因为变量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;
Run Code Online (Sandbox Code Playgroud)

后来,我创建了一个带有标题的示例对象,使用原始操作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); 
Run Code Online (Sandbox Code Playgroud)

输出为(按预期):

First
First changed
First
Run Code Online (Sandbox Code Playgroud)

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

First
First changed
First
Run Code Online (Sandbox Code Playgroud)

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

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;
Run Code Online (Sandbox Code Playgroud)

完整的源代码:

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);
Run Code Online (Sandbox Code Playgroud)

Sim*_*ght 5

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

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

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

我认为可以在return语句中复制它,但除此之外,是的(在某些情况下,涉及有限的类型,您可以“就地构建对象”,但是在语言标准版本之间规则有所变化,所以我m不确定;请参阅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;
Run Code Online (Sandbox Code Playgroud)