首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Ada记录的缺失特征

Ada记录的缺失特征
EN

Stack Overflow用户
提问于 2014-12-09 15:24:51
回答 2查看 561关注 0票数 0

考虑以下C++代码:

代码语言:javascript
复制
class Person
{
public:
    const std::string Name;
    int Weight = 0;
    Person(std::string AssignName) : Name(AssignName)
    {}
};

void Dinner(Person & ModifyPerson)
{
    ModifyPerson.Weight += 2;
}

名称是常量,在创建人员时首先初始化它。重量是可以调整的。

代码语言:javascript
复制
Person Person0("Conny");
Dinner(Person0);

让我们在Ada中试试这个:

代码语言:javascript
复制
type Person is record
    Name : constant String;
    Weight : Integer := 0;
end record;

Person0 : Person := Person'(Name => "Abby");

这个人的名字应该永远是"Abby“,因为它的常数和重量应该是可修改的,0应该是可有可无的。

由于Ada记录不允许以下内容,因此无法工作:

  • 恒定场
  • 字段类型的未指定范围
  • 限制初始化列表,即只分配名称并将权重=0作为缺省值。

如何在Ada代码中执行C++代码?

在C++中,我可以通过派生来扩展人。在Ada中,我们使用标记的记录。但是有标记的记录也不起作用。

如何在Ada代码中使用Person的可扩展功能完成C++代码?

EN

回答 2

Stack Overflow用户

发布于 2014-12-09 16:45:26

在Ada中,您首先决定Person能做什么和不能做什么,并设计接口。实现将在稍后进行。

据我从你们班看到的,你想让一个人:

  1. 有一个不变的名字(婚姻可能是个问题,但没关系)
  2. 有一个可变的权重,初始化为0
  3. 有能力增加或减轻体重。
  4. 从讨论中可以扩展(子类)

现在,Ada记录就像一个Struct,但我们需要的不仅仅是这个,通常将数据类型及其操作封装在一起的方法是一个Package。(这与C++命名空间也有一些共同之处,它还使主名称空间保持整洁)

代码语言:javascript
复制
Package Person_Pack is
  -- tagged for extensibility and other goodies
  type Person (Name_Length : Natural) is tagged private;
  function Name (P:Person) return String;
  function Weight (P:Person) return Natural;
  procedure Gain_Weight (P: in out Person; Increment : Integer);
  -- Explicit constructor, like "object factory" pattern
  function Birth(Name : String) return Person;
private
  -- none of your business yet...
end Person_Pack;

这就是接口(将其保存为"person_pack.ads")。这里有一个getter方法,但是没有设置名称的方法,我们保证了Person.Name的稳定性。

私有部分包含类型声明的细节,这样客户端代码就可以为Person分配空间,而基本上没有其他原因。所以,除了公共接口之外,不要篡改记录字段.我觉得我不需要说出为什么这是件好事?所以私人部分看起来就像

代码语言:javascript
复制
private
  type Person (Name_Length : Natural) is tagged record
    Name   : String(1 .. Name_Length);
    Weight : Integer := 0;
  end record;
end Person_Pack;

这是一个受歧视的记录,因此我们可以直接将名称存储在记录中,而不是使用Ada.Containers (与STL最接近的值)甚至Unbounded_String。这是一个实现细节,因为它仅限于私有部分,如果我们稍后在不更改接口并重新编译的情况下更改它,客户端代码仍然可以工作。

实现在包主体"person_pack.adb“中。

代码语言:javascript
复制
Package Body Person_Pack is
  function Name (P:Person) return String is
  begin
    return P.Name;
  end Name;

  function Weight (P:Person) return Natural is
  begin
    return P.Weight;
  end Weight;

  procedure Gain_Weight (P: in out Person; Increment : Integer) is
  begin
    P.Weight := P.Weight + Increment;
  end Gain_Weight;

  function Birth(Name : String) return Person is
    baby : Person(Name'Length);
  begin
    baby.Name := Name;
    baby.Weight := 0;
    return baby;
  end Birth;

end Person_Pack;

使用(以main.adb形式保存):

代码语言:javascript
复制
with Person_Pack; use Person_Pack;

procedure Main is

  -- type extension : refactor this into another package...
  type Employee is new Person with
    record
      Salary : Integer;
    end record;

  function Birth(Name : String) return Employee is
    baby : Person(Name'Length) := Birth(Name);
  begin
    return (baby with Salary => 0);
  end Birth;

  Abby : Person := Birth("Abigail");
  John : Employee := Birth("John");

  procedure Dinner (Gourmand : in out Person) is
  begin
    Gourmand.Gain_Weight(2);
  end Dinner;

begin
  Dinner(Abby);
end Main;

用下列方法汇编:

代码语言:javascript
复制
gcc -c -gnat2012 main.adb
gcc -c -gnat2012 person_pack.adb
gnatbind -x main.ali; gnatlink main.ali
票数 8
EN

Stack Overflow用户

发布于 2014-12-09 16:35:54

公共数据成员在任何面向对象的语言中都是不受欢迎的。因此,即使在C++中,我也希望具有坚实设计背景的人告诉您将NameWeight放在private:部分,并添加getter和setter方法来检索和设置字段。当然,您不会有Name的设置器,因为它是不可更改的。

阿达也是一样。将record设置为私有:

代码语言:javascript
复制
    type Person is private;  --or
    type Person is tagged private;

    function Make_Person (Name : String; Weight : Integer := 0) return Person;

    function Get_Name (X : Person) return String;

    function Get_Weight (X : Person) return Integer;
    procedure Set_Weight (X : in out Person; Weight : Integer);

private

    type Person is record --or
    type Person is tagged record 
        Name : Ada.Strings.Unbounded.Unbounded_String;
        Weight : Integer;
    end record;

Unbounded_String是处理长度可以动态变化的字符串变量或记录字段的常用方法。有关如何使用此包以及如何在Unbounded_StringString类型之间进行转换的信息,请参见Unbounded_String。这些转换只会出现在定义Person的包的主体中;使用Person的客户端包不必担心它。

如果将Person设置为tagged record,则仍然可以使用“点”符号来访问函数:

代码语言:javascript
复制
P : Person;

...

Name : String := P.Get_Name;       -- calls the getter function
Weight : Integer := P.Get_Weight;  -- calls the getter function

P.Set_Weight (P.Get_Weight + 2);

我不能对你说的“标记的记录也不起作用”的说法作出回应,因为你没有提供任何细节。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27382575

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档