Полиморфный указатель на родительский класс не работает

Рассмотрим следующую структуру классов, которая включает три отдельных модуля:

! ----------------------- в файле af

  module parent_body_mod
  type :: face
     class(parent_body), pointer :: bPtr
  end type
  type, abstract :: parent_body
     integer i
     type(face) :: f
  end type
  end module parent_body_mod

! ------------------------ в файле bf

  module body_mod
  use parent_body_mod

  type, extends(parent_body) :: body
  end type

  interface body
     procedure :: new_body
  end interface

  contains

  function new_body() result(b) 
  type(body), target :: b
  b%i = 123
  b%f%bPtr => b
  end function
  end module body_mod

! --------------------------- в файле cf

  module body_group_mod
  use body_mod
  type :: body_group
     type(body), allocatable :: b
  end type
  interface body_group
     procedure :: new_body_group
  end interface
  contains 
  function new_body_group() result(bg)
  type(body_group) :: bg

  allocate(bg%b)
  bg%b = body()

  end function
  end module body_group_mod

! ------------------- Основная программа

  use body_group_mod

  type(body_group) :: my_bg

  my_bg = body_group()      

  print *, my_bg%b%f%bPtr%i

  end

!--------------------------------------

Ожидаемый результат - 123, тогда как фактический результат - что-то случайное. Код скомпилирован с использованием ifort версии 18.0.1. Обратите внимание, что та же проблема не возникает при использовании самого класса "body", то есть следующее прекрасно работает:

type(body), allocatable :: my_b

allocate(my_b)

my_b = body()

print *, my_b%f%bPtr%i ! This produces 123 as expected.

Любая помощь приветствуется.

1 ответ

Решение

Код не соответствует.

Указатели, связанные с несохраненными локальными переменными процедуры, становятся неопределенными, когда выполнение процедуры завершается (F2008 16.5.2.5 (5)). Результат функции b в функции new_body считается такой локальной переменной (F2008 1.3.154.1), следовательно, компонент указателя b%f%bPtr становится неопределенным после вызова функции.

Результаты функций немного отличаются от других локальных несохраненных переменных тем, что их значение доступно дольше, чем существует переменная - см. Примечание 12.41 к F2008.

Другой способ мышления о проблемах заключается в том, что с заявлением bg%b = body(), тело с левой стороны - это объект, отличный от тела с правой стороны. Назначение просто копирует значение правого объекта - как только это назначение завершено, правый объект перестает существовать. Нигде нет кода, чтобы сказать, что когда передается значение объекта body - компонент указателя должен быть обновлен, чтобы ссылаться на левую переменную, которая назначается. Также обратите внимание, что левая сторона bg%b не имеет атрибута TARGET - так что в любом случае указатель не может быть правильно связан с ним.

Другие вопросы по тегам