通用接口和运算符重载 - 如何将通用接口块中的过程设置为在模块中私有?

Generic interfaces and operator overloading - how to set procedure from generic interface block to be private in module?

我的 IDE 是:Code::Blocks 20.03 (MinGW 9.2.0)

这是我的代码:

module mod_kompleks

  use, intrinsic :: iso_c_binding, only : rp => c_double

  implicit none

  type, public :: kom_bro

    real(rp), private :: rea
    real(rp), private :: img

    contains

      procedure, pass(kdt), private :: kom_bro_ini
      procedure, pass(kdt),  public :: uzm_rea => uzm_pod_rea
      procedure, pass(kdt),  public :: uzm_img => uzm_pod_img
      procedure, pass(kdt), private :: kom_bro_sab

      generic, public :: operator(+) => kom_bro_sab

  end type kom_bro

  interface kom_bro

    module procedure kom_bro_kon

  end interface kom_bro

  private :: kom_bro_kon

contains

  function kom_bro_kon( bro_rea, bro_img ) result( bro )

    real(rp), intent(in) :: bro_rea
    real(rp), intent(in) :: bro_img
    type(kom_bro)        :: bro

    call bro%kom_bro_ini(bro_rea, bro_img)

  end function kom_bro_kon

  subroutine kom_bro_ini(kdt, dio_rea, dio_img)

    class(kom_bro), intent(out) :: kdt
     real(rp),      intent(in)  :: dio_rea
     real(rp),      intent(in)  :: dio_img

     kdt%rea = dio_rea
     kdt%img = dio_img

  end subroutine kom_bro_ini

  function uzm_pod_rea( kdt ) result( rez )

    class(kom_bro), intent(in) :: kdt
     real(rp)                  :: rez

     rez = kdt%rea

  end function uzm_pod_rea

  function uzm_pod_img( kdt ) result( rez )

    class(kom_bro), intent(in) :: kdt
     real(rp)                  :: rez

     rez = kdt%img

  end function uzm_pod_img

  function kom_bro_sab( kdt, bro ) result( rez )

    class(kom_bro), intent(in) :: kdt
    class(kom_bro), intent(in) :: bro
     type(kom_bro)             :: rez

     rez%rea = kdt%rea + bro%rea
     rez%img = kdt%img + bro%img

  end function kom_bro_sab

end module mod_kompleks

program kompleksni_broj

  use, non_intrinsic :: mod_kompleks

  implicit none

  type(kom_bro) :: broj_01, broj_02, broj_03

  broj_01 = kom_bro(1.1_rp,2.2_rp)

  print '(1x,f4.2,1x,"j",1xf4.2)', broj_01%uzm_rea(), broj_01%uzm_img()

  broj_02 = kom_bro(3.3_rp,4.4_rp)

  print '(1x,f4.2,1x,"j",1xf4.2)', broj_02%uzm_rea(), broj_02%uzm_img()

  broj_03 = broj_01 + broj_02

  print '(1x,f4.2,1x,"j",1xf4.2)', broj_03%uzm_rea(), broj_03%uzm_img()

end program kompleksni_broj

我的目的是禁止在 mod_kompleks 模块外访问 kom_bro_sab 过程。如果我想在主程序中用实部和虚部的值构造一个复数,在输入 kom 这个词后,我有机会选择过程 kon_bro,这当然是我想要的,但紧接着该功能让我有机会选择程序 kom_bro_sab。我怎样才能防止这种情况发生(我只希望过程 kom_bro_sab 和运算符 + 可见)? 我将添加我得到的截图,即使类型绑定过程是私有的:

简而言之

kom_bro_sab 函数具有(默认)访问 属性 public 这就是为什么您可以在主程序中访问 kom_bro_sab

说明

函数 kom_bro_sab 与任何其他函数一样被导出,因为它的访问 属性 是 public。 这是因为默认情况下访问权限 属性 是 public 且未在此处更改。

不要被行 procedure, pass(kdt), private :: kom_bro_sab 搞糊涂了。 这里定义了一个 type-bound 过程 kom_bro_sab 并且可以访问 属性 private。 因此,您只能从其他类型绑定过程中调用此 属性。 您应该区分类型绑定过程和函数本身。

解决方案

有两种处理方法。

  1. 将默认访问权限 属性 更改为 private 并仅明确定义 public 实体。这也使得快速浏览模块以查看实际导出了哪些实体变得更加容易。
module mod_kompleks
  use, intrinsic :: iso_c_binding, only : rp => c_double
  implicit none
  private
  public kom_bro
  
  type kom_bro
...
end module
  1. 您可以通过显式定义 publicprivate 属性来保持您正在做的事情。然后你只需要添加一行(参见包含 ADDED 的行)。
module mod_kompleks
  use, intrinsic :: iso_c_binding, only : rp => c_double
  implicit none
  type, public :: kom_bro
...
  end interface kom_bro
  private kom_bro_kon
  private kom_bro_sab     ! <- ADDED
...
end module

我缩短了你的代码,希望它仍然可以理解。

超载operator(+)工作

broj_03 = broj_01 + broj_02

我们要考虑三个不同的方面:

  • 模块程序kom_bro_sab
  • 具有绑定名称的特定类型绑定过程kom_bro_sab
  • 通用类型绑定接口operator(+)

其中每一个都有自己的可访问性,并且是不同的东西。

看看我们的声明。在

broj_03 = broj_01 + broj_02

我们可以看到,当我们考虑泛型 operator(+) 时,我们有左侧 class(kom_bro) 和右侧 class(kom_bro):我们匹配特定类型-绑定程序kom_bro_sab。我们可以在模块外进行评估,因为这个通用接口是public。此解析不需要特定类型绑定过程 public.

假设绑定名称是可访问的,前面的语句可以写成对特定类型绑定过程的引用,如下所示

broj_03 = broj_01%kom_bro_sab(broj_02)

最后,假设模块过程是可访问的,看起来像

broj_03 = kom_bro_sab(broj_01, broj_02)

我们可以独立控制对这些东西的访问。

在问题的代码中,您有特定的绑定 kom_bro_sab private,但是模块过程 kom_bro_sab 是 public 因为模块的默认可访问性是 public.

展示了如何将默认可访问性设置为私有,或者具有默认可访问性 public 但将模块过程设置为私有。您已经指定了对特定绑定和通用绑定的访问权限。