【问题标题】:Protected inheritance in Fortran 2003/2008Fortran 2003/2008 中的受保护继承
【发布时间】:2013-11-19 05:07:17
【问题描述】:

我正在寻找一种从后代类访问 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 可以在任何地方访问,并且只保护其值,不能在类之外更改)。

【问题讨论】:

    标签: inheritance fortran parent-child private


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 我相信 private 的 Fortran 定义是 protected 的 C++ 等价物。
    • @High Performance Mark:是的,我可以在同一个模块中包含基本类型及其子类型。这样,父类型的私有组件可以从子类型访问。然而,这会导致巨大的模块,特别是如果基类型有很多孩子,每个孩子都有自己的类型绑定过程等。我正在寻找一个更好的解决方案,在不同的文件中声明类型而不是一个巨大的文件,包括所有类型。
    • @SuperCow:不,Fortran 的私有属性具有“模块范围”。如果一个变量被声明为“私有”,那仅仅意味着它只能在模块内访问,而在外部是未知的,即使程序块使用了该模块。它与 C++ 的受保护属性无关。我实际上在寻找的是 C++ 在 Fortran 中的受保护属性的等价物。
    • huge modules -- 你这样写就好像这是件坏事:-)
    • 考虑一个名为“Drawable”的抽象类,以及另一个继承自“Drawable”的名为“Shape”的抽象类。现在考虑另外四个类:“Pixel”(继承自“Drawable”)和“Rectangle”、“Polygon”、“Texture”、“Sprite”(都继承自“Shape”。这是一个“真实世界”示例(实际上,它是我正在实现的 OpenGL 图形库的一部分)。总共有 6 个类(将来可能还会更多),它们都定义了自己的方法。它们必须在同一个模块中,因为“private”属性的工作方式。这已经导致代码难以维护。
    【解决方案2】:

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

    正如您在 cmets 中对 Mark 的回答所指出的,可访问性基于模块,而不是类型。

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

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

    【讨论】:

    • 我已经在考虑子模块了,它可以相当优雅地解决问题。不幸的是,子模块是 Fortran 2008 的一个功能,我的编译器(gfortran 4.8.2)尚未实现,即使使用 -std=2008 标志:子模块语句被编译器视为“不可分类的语句”。跨度>
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 2013-05-18
      • 1970-01-01
      • 2010-09-14
      • 2016-09-04
      • 2020-09-09
      • 2016-06-12
      • 2015-01-19
      • 2014-06-09
      • 1970-01-01
      相关资源
      最近更新 更多