我的问题包含一段较长的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;
我认为,第二种方法是在堆上创建对象,然后在执行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_Title
和Second_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;
答案 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;