Защищенное наследование в 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, просто избегает огромных файлов. Однако он работает как обходной путь.