Полиморфный указатель на родительский класс не работает
Рассмотрим следующую структуру классов, которая включает три отдельных модуля:
! ----------------------- в файле 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 - так что в любом случае указатель не может быть правильно связан с ним.