12

我正在寻找一种从后代类访问 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++ 具有用于此目的的“受保护”属性,但据我所知,Fortran 2003 中的“受保护”属性具有不同的含义(它使 A%x 可以在任何地方访问,并且只保护其值,不能在类之外更改)。

4

3 回答 3

10

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

正如您在 Mark's answer 的评论中所指出的,可访问性基于模块,而不是类型。

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

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

于 2013-11-07T19:41:44.793 回答
5

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

我真的不明白你的问题,或者我不明白你想要做什么。我同意您的观点,您的选择 (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

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

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

于 2013-11-07T17:53:07.110 回答
0

正如 Mark 建议的那样,在单个模块中实现所有内容可以绕过这个问题,但会导致“真实世界”程序的模块很长,这很不方便。

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

于 2013-11-07T21:08:55.087 回答