通过强类型和运算符重载进行简单的单元检查

mar*_*rbu 4 ada

我正在阅读Ada 中的强类型,重点是单元检查,并决定自己测试这种幼稚的方法:

procedure Example is
  type Meters is new Float;
  type Meters_Squared is new Float; 
  function "*" (Left, Right : Meters) return Meters_Squared is
  begin
    return Meters_Squared(Float(Left)*Float(Right));
  end;
  len_a : Meters := 10.0;
  len_b : Meters := 15.0;
  surface : Meters_Squared;
  len_sum : Meters;
begin
  len_sum := len_a + len_b; -- ok
  surface := len_a * len_b; -- ok
  len_sum := len_a * len_b; -- invalid
end Example;
Run Code Online (Sandbox Code Playgroud)

现在我知道这实际上并不是实用的方法,我只是将其作为一种学习经验来尝试。根据我到目前为止的尝试,我一定遗漏了一些东西,因为当我尝试编译上面列出的示例时,我没有收到任何错误:

$ make example
gcc -c example.adb
gnatmake example.adb
gnatbind -x example.ali
gnatlink example.ali
Run Code Online (Sandbox Code Playgroud)

当我删除重载乘法运算符的函数定义时,它会按预期失败:

$ make example
gcc -c example.adb
example.adb:14:20: expected type "Meters_Squared" defined at line 3
example.adb:14:20: found type "Meters" defined at line 2
make: *** [Makefile:6: example] Error 1
Run Code Online (Sandbox Code Playgroud)

考虑到这一点,我不明白怎么回事,用乘法运算符重载,编译器可确定与surface := len_a * len_blen_sum := len_a * len_b在同一时间。

Sim*_*ght 5

你的"*"重载就是这样;Meters继承

function "*" (Left, Right: Meters) return Meters;
Run Code Online (Sandbox Code Playgroud)

Float.

你可以做的是抑制继承的功能:

function "*" (Left, Right: Meters) return Meters
is abstract;
Run Code Online (Sandbox Code Playgroud)

在这种情况下,标记不需要的函数abstract会将其从重载解析的考虑中移除:在ARM 6.4(8) 中,我们有

... 名称或前缀不应解析为表示抽象子程序,除非它也是调度子程序。

并且Meters不是标记类型,因此"*"不是调度。

您还可以声明一个非重载子程序abstract

function "and" (Left, Right : Meters) return Meters
is abstract;
Run Code Online (Sandbox Code Playgroud)

GNAT 所说的cannot call abstract subprogram "and",因为 ARM 3.9.3(7)

  • 带注释的 Ada 参考手册在 [3.9.3](http://www.ada-auth.org/standards/aarm12_w_tc1/html/AA-3-9-3.html) 中说:{AI95-00310-01}在 Ada 2005 中,未标记类型的抽象基元子程序可用于“取消定义”操作。 (2认同)