我正在阅读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_b和len_sum := len_a * len_b在同一时间。
你的"*"重载就是这样;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)。