Защищенное наследование в Fortran 2003/2008

Я ищу способ доступа к частным компонентам класса Fortran (производный тип в терминологии Fortran) из класса потомков. Например, предположим, что класс A имеет компонент x, объявленный как закрытый. Теперь рассмотрим второй класс B, который наследуется от базового класса A. В этом случае класс B не имеет прямого доступа к x, поэтому любая попытка доступа к B% x недопустима. Два решения, о которых я могу думать, следующие:

(1) Объявить x общедоступным. Это, однако, сделает x доступным по всему миру, что нарушает скрытие данных и, следовательно, оно отвергается как приемлемое решение проблемы.

(2) Внедрить процедуры получения/установки A% x, такие как A% getX() и A% setX(). Это не только громоздко, но также позволит (косвенный) доступ к A% x всюду в программе - не только в дочерних классах.

Я хочу, чтобы получить доступ к A% x из дочерних классов, но в противном случае x должен быть недоступен в другом месте. С++ имеет атрибут "protected" для этой цели, но насколько мне известно, "защищенный" атрибут в Fortran 2003 имеет другое значение (он делает A% x доступным везде и только защищает его значение, которое не может быть изменено вне класса).

Ответ 1

Язык не имеет такой возможности в общем смысле (помимо того, что делает все в одном модульном подходе, который предлагает High Performance Mark), и вы не одиноки в этом.

Как вы заметили в комментариях к ответу Mark, доступность основана на модулях, а не на типах.

Обратите внимание, что использование подмодулей, возможно, частично решит вашу проблему. Вы используете один большой подход к модулю, предложенный HIgh Performance Mark, но этот модуль можно разделить между несколькими программными модулями. Процедуры, которые реализуют привязки для типа, могут быть представлены вместе в подмодуле в виде отдельных процедур модуля, сам модуль содержит только определения типов и отдельные интерфейсные тела. Поскольку подмодули являются концептуально частью своего предкового модуля, все компоненты и типы в модуле, которые являются частными в модуле, все еще доступны.

Одно концептуальное различие между Fortran и другими языками, такими как С++ (скажем), состоит в том, что процедуры, которые на самом деле делают что-то, не являются "частью" типа - вместо этого типы имеют привязки, относящиеся к процедуре. Привязки из нескольких типов могут ссылаться на одну процедуру. Следовательно, хотя внутри определения типа ясно, работаете ли вы в области, которая является расширением родительского типа, вне определения типа она менее понятна. Языковой объект, который реализует эту функцию, должен каким-то образом учитывать эту разницу.

Ответ 2

Это скорее расширенный комментарий, чем ответ...

Я действительно не понимаю ваш вопрос, или, возможно, я не понимаю, что вы пытаетесь сделать. Я согласен с вами в том, что ваш выбор (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

to

procedure, pass, private :: getc1

процедура больше не используется вне модуля. Это выглядит как подтип, имеющий доступ к частным компонентам супертипа, без доступа к внешнему миру.

Этот код соответствует стандарту, так как я и мой компилятор понимают стандарт.

Ответ 3

Реализация всего в одном модуле, как предложил Марк, обходит проблему, но приводит к очень длинным модулям для программ "реального мира", что не удобно.

Субмодулы - это ответ на мой вопрос, как предложил Янх. К сожалению, подмодули - это функция Fortran 2008, еще не реализованная в gfortran (и, вероятно, большинство компиляторов там). В качестве временного обходного пути я закончил использование одного модуля, определяющего все типы, а методы, связанные с этими типами, определены в отдельных файлах, которые затем включаются в основной модуль с помощью команды "включить". Это по существу решение Mark, просто избегает огромных файлов. Однако он работает как обходной путь.