我的问题包含一段较长的Ada代码。基本上,我尝试以面向对象的方式为带有标题的消息建模。两个原语操作Create_Message和Create_Message_Access可以用来创建具体消息对象。我不确定原始操作是否应返回类型Message_Type或Message_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)
可以使用两个原始操作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)
| 归档时间: |
|
| 查看次数: |
87 次 |
| 最近记录: |