在Fortran中访问子声明类型的问题

时间:2019-01-16 12:05:57

标签: class oop fortran intel-fortran

考虑以下代码

  module class_type

  implicit none
  class(*), pointer :: fnzo => null()


  type, abstract :: gen

     real :: ss
     integer :: sdsd
     class(gen), pointer    :: next =>null()
  end type

  type, extends(gen) :: final1

     real :: ss1

  end type final1

  type, extends(gen) :: final2

  real :: x1(10)

  end type


  end module class_type



  program test_class

  use class_type

  implicit none

  class(gen), pointer :: test
  type(final1) :: test1
  allocate(test, source = test1)

  print*, test% ss1




  end program

我正在尝试制定一个链接的列表,其中每个下一个元素都继承final1final2。目前,仅测试简单的案例,而我不明白为什么我无法访问test%ss1。任何人都可以帮助

2 个答案:

答案 0 :(得分:2)

至于“为什么我们不能访问test% ss1”,以下代码对于考虑原因可能很有用。在这段代码中,我得到用户输入(inp,并确定ptr指向类型为test1还是test2的变量。如果ptr指向变量test2,则访问ptr% ss1显然是没有意义的,因此编译器需要防止这种错误的访问。我认为这就是为什么除非提供gen(用于内存中的实际数据),否则编译器仅允许访问select type(=声明的类型)的组件的原因。

program test_class
  use class_type
  implicit none
  class(gen), pointer  :: ptr    !! parent type
  type(final1), target :: test1  !! child type
  type(final2), target :: test2  !! child type
  integer :: inp

  print *, "input some integer"
  read *, inp

  if ( inp == 1 ) ptr => test1
  if ( inp == 2 ) ptr => test2

  print*, "ptr% ss = ", ptr% ss   !! OK

  ! print*, "ptr% ss1 = ", ptr% ss1  !! error (Line1)

  select type ( ptr )
    type is ( final1 ); print*, "ss1 = ", ptr% ss1  !! OK
    type is ( final2 ); print*, "x1  = ", ptr% x1   !! OK
  endselect

end program

如果Line1取消注释,则会出现错误(使用gfortran-8)

   print*, "ptr% ss1 = ", ptr% ss1  !! error
                             1
Error: 'ss1' at (1) is not a member of the 'gen' structure; did you mean 'ss'?

我猜情况与其他(静态类型的)语言相似。例如,当我们访问ptr->b时,以下C ++代码给出了错误。

#include <iostream>
using namespace std;

struct A {
    int a = 1;
};
struct B : A {
    int b = 100;
};

int main() {
    A *ptr;
    ptr = new B;
    cout << ptr->a << endl;     // 1
    // cout << ptr->b << endl;  // error: 'struct A' has no member named 'b'
    delete ptr;
}

答案 1 :(得分:0)

为了访问ss1,您需要在抽象类中有一个指向子对象的指针。指针可以是您要定义的任何类型的扩展。由于您的链表具有两个不同的类型扩展名,因此您需要在抽象类中声明两个子指针。

module class_type

  implicit none
  class(*), pointer :: fnzo => null()


  type, abstract :: gen

     real :: ss
     integer :: sdsd
     class(gen), pointer    :: next =>null()
     type(final1), pointer  :: child
  end type

  type, extends(gen) :: final1

     real :: ss1

  end type final1

  type, extends(gen) :: final2

     real :: x1(10)

  end type final2


end module class_type



program test_class

  use class_type

  implicit none

  class(gen), pointer  :: test
  type(final1), target    :: test1

  allocate(test, source=test1)

  test1% ss1 = 20.0
  test% child => test1

  write(*,*) test1% ss1

  write(*,*) test% child% ss1

end program test_class

编译和执行时,您会看到:

   20.00000    
   20.00000