Как переопределить конструктор конструктора в Фортране
-
27-09-2019 - |
Вопрос
В настоящее время можно переопределить конструктор конструктора в Fortran? Я видел предложил такие примеры, как это (например, в спецификации Fortran 2003):
module mymod
type mytype
integer :: x
! Other stuff
end type
interface mytype
module procedure init_mytype
end interface
contains
type(mytype) function init_mytype(i)
integer, intent(in) :: i
if(i > 0) then
init_mytype%x = 1
else
init_mytype%x = 2
end if
end function
end
program test
use mymod
type(mytype) :: x
x = mytype(0)
end program
Это в основном генерирует кучу ошибок из-за избыточных имен переменных (например, ошибка: производный атрибут конфликтов «MyType» с атрибутом процедуры в (1)). Долбатичная копия примера Fortran 2003 генерирует подобные ошибки. Я пробовал это в GFORTRAN 4.4, IFORT 10.1 и 11.1, и все они создают одинаковые ошибки.
Мой вопрос: это просто невыполненная особенность Fortran 2003? Или я реализую это неправильно?
Редактировать: я наткнулся на отчет об ошибке и ан Объявлен патч к Губерану относительно этой проблемы. Тем не менее, я пытался использовать ноябрьскую сборку GCC46 без удачи и подобных ошибок.
Редактировать 2: Приведенный выше код появляется с использованием Intel Fortran 12.1.0.
Решение
Я консультировался с моей копией стандарта Fortran 2008. Это позволяет вам определить общий интерфейс с тем же именем, что и полученный тип. Мой компилятор (Intel Fortran 11.1) не будет компилировать код, хотя я оставил подозревающуюся (без копии стандарта 2003 года в руку), что это еще не только одноместный характер стандарта Fortran 2003.
Кроме того, в вашей программе есть ошибка. Декларация вашей функции:
type(mytype) function init_mytype
integer, intent(in) :: i
Определяет существование и намерение аргумента, который отсутствует в спецификации функций, которые, возможно, должны быть переписаны как:
type(mytype) function init_mytype(i)
Другие советы
В настоящее время можно переопределить конструктор конструктора в Fortran?
Нет. Во всяком случае, даже использование вашего подхода, совсем не о переопределении конструктора. Основная причина заключается в том, что конструктор конструкции # OOP конструктор. Есть немного сходства, но это просто еще одна идея.
Вы не можете использовать вашу неиспорченную функцию в экспрессии инициализации. Вы можете использовать только константу, массивную или структуру конструктора, внутренние функции, ... Для получения дополнительной информации посмотрите на 7.1.7. Выражение инициализации в проекте Fortran 2003.
Принимая этот факт во внимание, я полностью не понимаю, что такое реальная разница между
type(mytype) :: x
x = mytype(0)
а также
type(mytype) :: x
x = init_mytype(0)
И что такое весь точка использования интерфейсного блока внутри модуля MyMod.
Ну, честно говоря, есть разница, огромный - первый способ вводит в заблуждение. Эта функция не является конструктором (потому что в Fortran нет конструкторов OOP), это инициализатор.
В мейнстрим Ооп Конструктор несет ответственность за последовательно выполнение двух вещей:
- Выделение памяти.
- Инициализация участника.
Давайте посмотрим на некоторые примеры инстанционных классов на разных языках.
В Джава:
MyType mt = new MyType(1);
Очень важный факт скрыт - тот факт, что объект на самом деле является указателем для варибата типа класса. Эквивалент в C ++ будет распределение на кучу с использованием:
MyType* mt = new MyType(1);
Но на обоих языках можно увидеть, что два конструкторных обязанностя отражаются даже на уровне синтаксиса. Он состоит из двух частей: ключевое слово New (распределение) и имя конструктора (инициализация). В Объектив-C. Синтаксис этот факт еще больше подчеркивается:
MyType* mt = [[MyType alloc] init:1];
Однако много раз вы можете увидеть некоторую другую форму вызова конструктора. На случай, если Распределение на стек C ++ Использует специальную (очень плохое) синтаксическое строительство
MyType mt(1);
Что на самом деле вводит в заблуждение, что мы можем просто не учитывать это.
В Питон
mt = MyType(1)
И тот факт, что объект на самом деле является указателем, и тот факт, что выделение происходит сначала скрыты (на уровне синтаксиса). И этот метод называется ... __init__
Действительно O_O так вводит в заблуждение. С ++ распределение стека исчезает по сравнению с этим. знак равно
В любом случае, идея иметь конструктор На языке подразумевают способность делать распределение инициализации в одном утверждении используя особый вид метода. И если вы думаете, что это «истинное ООП», у меня есть плохие новости для вас. Четное Болтовня не имеет конструкторов. Отказ Это только конвенция, чтобы иметь new
Способ на самих классах (они синглтон объекты мета классов). То Шаблон заводской конструкции используется на многих других языках для достижения такой же цели.
Я читал где-то, что концепции модулей в Форттрену были вдохновлены Модулом-2. И мне кажется, что особенности ООП вдохновлены Оберон-2.. Отказ Также нет конструкторов в Оберон-2. Но есть, конечно, чистое распределение с предшественнированной процедурой новой (например, выделить в Фортране, но выделение это утверждение). После распределения вы можете (следует на практике) вызовите какой-то инициализатор, который является просто обычным методом. Ничего особенного там.
Таким образом, вы можете использовать какие-то фабрики для инициализации объектов. Это то, что вы на самом деле делали модули вместо объектов Singleton. Или лучше сказать, что они (программисты Java / C # / ... программисты) используют методы объектов Singleton вместо обычных функций из-за отсутствия более позднего (без модулей - никаких способов иметь обычные функции, только методы).
Также вы можете использовать подпрограмму связанного типа.
MODULE mymod
TYPE mytype
PRIVATE
INTEGER :: x
CONTAINS
PROCEDURE, PASS :: init
END TYPE
CONTAINS
SUBROUTINE init(this, i)
CLASS(mytype), INTENT(OUT) :: this
INTEGER, INTENT(IN) :: i
IF(i > 0) THEN
this%x = 1
ELSE
this%x = 2
END IF
END SUBROUTINE init
END
PROGRAM test
USE mymod
TYPE(mytype) :: x
CALL x%init(1)
END PROGRAM
INTENT(OUT)
для this
arg of. init
Подпрограмма, кажется, в порядке. Поскольку мы ожидаем, что этот метод называется только один раз и сразу после распределения. Может быть, хорошая идея контролировать, что это предположение не будет неправильно. Добавить немного логического флага LOGICAL :: inited
к mytype
, проверьте, есть ли это .false.
и установить его .true.
При первой инициализации и сделайте что-то еще при попытке повторной инициализации. Я определенно помню некоторую нить об этом в Google группах ... Я не могу его найти.