Fortran 2003/2008 中的受保护继承



我正在寻找一种从后代类访问Fortran类(Fortran术语中的派生类型)的私有组件的方法。例如,假设类 A 有一个组件 x,该组件声明为私有。现在考虑第二个类 B,它继承自基类 A。在这种情况下,类 B 无法直接访问 x,因此不允许任何访问 B%x 的尝试。我能想到的两个解决方案是:

(1) 将 x 声明为公共。但是,这将使x全局可访问,从而滥用数据隐藏,因此拒绝将其作为问题的可接受解决方案。

(2) 实现获取/设置 A%x 的过程,例如 A%getX() 和 A%setX()。这不仅很麻烦,而且还允许(间接)访问程序中任何地方的 A%x - 而不仅仅是在子类中。

我想要的是一种从 A 的子类访问 A%x 的方法,但否则 x 应该在其他地方无法访问。C++具有用于此目的的"protected"属性,但据我所知,Fortran 2003 中的"protected"属性具有不同的含义(它使 A%x 可以在任何地方访问,并且只保护其值,不能在类之外更改)。

该语言在一般意义上没有这种能力(除了高性能标记建议的一个模块方法中做所有事情之外),而且你并不是唯一一个想要这样做的人。

正如您在 Mark 答案的评论中指出的那样,可访问性基于模块,而不是类型。

但请注意,使用子模块可能会部分解决您的问题。 您使用 HIgh 性能标记建议的一个大模块方法,但该模块可以拆分为多个程序单元。 实现类型绑定的过程可以作为单独的模块过程一起在子模块中提供,然后模块本身仅保存类型定义和单独的接口主体。 由于子模块在概念上是其祖先模块的一部分,因此模块中私有模块中的任何组件和类型仍然可以访问。

Fortran 与其他语言(如 C++(例如))之间的一个概念区别是,实际执行操作的过程不是类型的"部分",而是类型具有引用过程的绑定。 来自多个类型的绑定可以引用一个过程。 因此,虽然在类型定义内部很清楚您是否在父类型的扩展范围内工作,但在类型定义之外则不太清楚。 实现此功能的语言工具需要以某种方式适应这种差异。

这可能是一个扩展的评论而不是答案......

我真的不明白你的问题,或者也许我不明白的是你想做什么。 我同意你的看法,你的选择(1)没有吸引力,我们希望private组件是私有的。

但是当我谈到你的观点(2)时,我可以写一个这样的模块:

module types
  type :: supertype
     integer, private :: c1 = 1
  end type supertype
  type, extends(supertype) :: subtype
     integer :: c2
   contains
     procedure, pass :: getc1
  end type subtype
contains
  integer function getc1(this)
   class(subtype), intent(inout) :: this
   this%c1 = 12      ! Just to show that the sub-type can set super-type components
   getc1 = this%c1   ! Return the latest value of c1 
  end function getc1
end module types

编译时没有错误(Intel Fortran 13.something)。 这会使类型绑定过程getc1可供模块的所有用户使用。 但是,如果我将过程声明从

procedure, pass :: getc1

procedure, pass, private :: getc1

该过程在模块外部不再可用。在我看来,这看起来像一个子类型,可以访问超类型的私有组件,而不会泄露给外部世界。

此代码符合标准,因为我和我的编译器都了解该标准。

正如Mark所建议的那样,在单个模块中实现所有内容绕过了这个问题,但导致"现实世界"程序的模块非常长,这并不方便。

子模块是我问题的答案,正如 IanH 所建议的那样。不幸的是,子模块是Fortran 2008的一个功能,尚未在gfortran中实现(可能还有大多数编译器)。作为临时解决方法,我最终使用了一个定义所有类型的模块,并且与这些类型相关的方法在单独的文件中定义,然后使用"include"命令将其包含在主模块中。这本质上是马克的解决方案,只是避免了大文件。但是,它作为一种解决方法。

最新更新