我试图向用户隐藏库的某些方面并阅读 RM 进行类型转换,我不明白为什么以下代码会失败。
用户将实例化 root.child.concrete.concrete_t,然后将调用传递该实例的 root.p_userInterface,但在 root.adb 上引发编译错误:无效标记转换,与定义的类型“child_t'class”不兼容root-child.ads:4
根广告:
limited with root.child;
package root is
procedure p_userInterface (obj : in out root.child.child_t'Class);
private
type root_t is abstract tagged null record;
procedure p_primitive (this : in out root_t) is abstract;
end root;
根.adb:
with root.child;
package body root is
procedure p_userInterface (obj : in out root.child.child_t'Class) is
begin
-- error: invalid tagged conversion, not compatible with type "child_t'class" defined at root-child.ads:4
root_t'Class(obj).p_primitive;
end p_userInterface;
end root;
根-child.ads:
package root.child is
type child_t is abstract tagged private;
function f_getComponent(this : in child_t) return Integer;
private
type child_t is abstract new root_t with
record
component : Integer;
end record;
overriding
procedure p_primitive (this : in out child_t) is abstract;
end root.child;
根-child.adb:
package body root.child is
function f_getComponent(this : in child_t) return Integer is
begin
return this.component;
end f_getComponent;
end root.child;
根子concrete.ads:
package root.child.concrete is
type concrete_t is new child_t with private;
procedure p_setAnotherComponent (this : in out concrete_t;
c : Boolean);
function f_getAnotherComponent (this : concrete_t) return Boolean;
private
type concrete_t is new child_t with
record
anotherComponent : Boolean;
end record;
overriding
procedure p_primitive (this : in out concrete_t);
end root.child.concrete;
根子concrete.adb:
package body root.child.concrete is
procedure p_primitive (this : in out concrete_t) is
begin
-- for example
this.anotherComponent := True;
end p_primitive;
procedure p_setAnotherComponent (this : in out concrete_t;
c : Boolean) is
begin
this.anotherComponent := c;
end p_setAnotherComponent;
function f_getAnotherComponent (this : concrete_t) return Boolean is
begin
return this.anotherComponent;
end f_getAnotherComponent;
end root.child.concrete;
为什么?我了解 root 的实现无法看到其 root.child 子包的私有部分,因此无法看到类型 child_t 正在私下扩展 root_t。我说的对吗?
我能以不同的方式实现类似的目标吗?我想将 p_primitive 隐藏给用户,因为它是为了执行内部操作,但如果可能的话,我想在内部调度它。
回答1
我想我终于实现了。这是对我有用的解决方案,仅适用于更改的单位,注释掉旧部分,因为我不能使用 html 罢工标签来划掉代码:
根广告:
--limited with root.child;
package root is
type root_t is abstract tagged null record;
procedure p_userInterface (obj : in out root_t'Class); --root.child.child_t'Class);
private
--type root_t is abstract tagged null record;
--procedure p_primitive (this : in out root_t) is abstract;
type hiddenRoot_t is abstract new root_t with null record;
procedure p_primitive (this : in out hiddenRoot_t) is abstract;
end root;
根.adb:
--with root.child; It was not needed before neither
package body root is
procedure p_userInterface (obj : in out root_t'Class) is --root.child.child_t'Class) is
begin
--root_t'Class(obj).p_primitive; -- invalid tagged conversion, not compatible with type "child_t'class"
hiddenRoot_t'Class(obj).p_primitive;
end p_userInterface;
end root;
根-child.ads:
package root.child is
--type child_t is abstract tagged private;
type child_t is abstract new root_t with private;
function f_getComponent(this : in child_t) return Integer;
private
--type child_t is abstract new root_t with
type child_t is abstract new hiddenRoot_t with
record
component : Integer;
end record;
overriding
procedure p_primitive (this : in out child_t) is abstract;
end root.child;
这样我就可以私下分派到concrete_t 类型的p_primitive 的实现,并且在main 上我可以确保concrete_t 的实例没有p_primitive 的可见性。对此解决方案的任何进一步评论将不胜感激,我不知道我是否遗漏了一些重要的东西,但似乎有效。我不知道这是否是正确的解决方案。