Возможно ли в настоящее время переопределить конструктор структуры в Fortran?
Нет. В любом случае, даже если вы используете ваш подход, это вовсе не переопределение конструктора. Основная причина в том, что структура конструктора # ООП конструктор. Есть некоторое сходство, но это просто другая идея.
Вы не можете использовать вашу не встроенную функцию в выражении инициализации. Вы можете использовать только конструктор констант, массивов или структур, встроенные функции, ... Для получения дополнительной информации взгляните на 7.1.7 Выражение инициализации в черновике Fortran 2003.
Принимая во внимание этот факт, я совершенно не понимаю, в чем реальная разница между
type(mytype) :: x
x = mytype(0)
и
type(mytype) :: x
x = init_mytype(0)
и в чем смысл использования блока INTERFACE в модуле mymod.
Ну, честно говоря, есть разница, огромная - первый путь вводит в заблуждение. Эта функция не является конструктором (поскольку в Фортране вообще нет конструкторов ООП), она является инициализатором.
В основном ООП конструктор отвечает за последовательное выполнение двух вещей:
- Распределение памяти.
- Инициализация элемента.
Давайте рассмотрим несколько примеров создания классов на разных языках.
In Java :
MyType mt = new MyType(1);
очень важный факт скрыт - тот факт, что объект на самом деле является указателем на переменную типа класса. Эквивалент в C ++ будет выделение в куче с использованием:
MyType* mt = new MyType(1);
Но в обоих языках видно, что две обязанности конструктора отражаются даже на уровне синтаксиса. Он состоит из двух частей: ключевое слово new (выделение) и имя конструктора (инициализация). В синтаксисе Objective-C этот факт еще более подчеркивается:
MyType* mt = [[MyType alloc] init:1];
Однако, часто вы можете видеть какую-то другую форму вызова конструктора. В случае выделения в стеке C ++ использует специальную (очень плохую) синтаксическую конструкцию
MyType mt(1);
что на самом деле настолько вводит в заблуждение, что мы можем просто не учитывать это.
В Python
mt = MyType(1)
и тот факт, что объект на самом деле является указателем, и тот факт, что выделение происходит первым, скрыты (на уровне синтаксиса). И этот метод называется ... __init__
! О_О Так вводит в заблуждение. Распределение стека С ++ исчезает по сравнению с этим. =) * +1062 *
В любом случае, идея иметь конструктор в языке подразумевает возможность выделить инициализацию в одном операторе , используя какой-то особый метод. И если вы думаете, что это «настоящий ООП», у меня для вас плохие новости. Даже Smalltalk не имеет конструкторов . Просто принято иметь метод new
для самих классов (они являются одноэлементными объектами мета-классов). Шаблон Factory Design используется во многих других языках для достижения той же цели.
Я где-то читал, что концепция модулей в Фортране была вдохновлена Модулой-2. И мне кажется, что функции ООП вдохновлены Oberon-2 . В Обероне-2 также нет конструкторов. Но есть, конечно, чистое распределение с предварительно объявленной процедурой NEW (как ALLOCATE в Fortran, но ALLOCATE является оператором). После выделения вы можете (на практике) вызвать некоторый инициализатор, который является обычным методом. Ничего особенного там нет.
Так что вы можете использовать какие-то фабрики для инициализации объектов. Это то, что вы на самом деле сделали, используя модули вместо одноэлементных объектов. Или лучше сказать, что они (программисты Java / C # / ...) используют методы одноэлементных объектов вместо обычных функций из-за отсутствия более поздних (нет модулей - нет способа иметь обычные функции, только методы).
Также вы можете использовать вместо этого SUBROUTINE с привязкой к типу.
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 из init
SUBROUTINE вроде бы хорошо. Потому что мы ожидаем, что этот метод будет вызываться только один раз и сразу после выделения. Может быть хорошей идеей контролировать, что это предположение не будет ошибочным. Чтобы добавить некоторый логический флаг LOGICAL :: inited
к mytype
, проверьте, является ли он .false.
и установите его на .true.
при первой инициализации, и сделайте что-нибудь еще при попытке повторной инициализации. Я определенно помню какую-то ветку об этом в группах Google ... Я не могу найти ее.