Как переопределить конструктор структуры в фортране - PullRequest
14 голосов
/ 24 ноября 2010

Возможно ли в настоящее время переопределить конструктор структуры в Фортране? Я видел такие примеры (например, в спецификации 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

Это в основном генерирует кучу ошибок из-за избыточных имен переменных (например, Ошибка: атрибут DERIVED mytype конфликтует с атрибутом PROCEDURE в (1)). Дословная копия примера с Фортраном 2003 приводит к аналогичным ошибкам. Я пробовал это в gfortran 4.4, ifort 10.1 и 11.1, и все они выдают одинаковые ошибки.

Мой вопрос: это просто невыполненная функция Fortran 2003? Или я неправильно это реализую?

Edit: я наткнулся на сообщение об ошибке и анонсированный патч для gfortran относительно этой проблемы. Однако я попытался использовать ноябрьскую сборку gcc46 без удачи и схожих ошибок.

Редактировать 2: Приведенный выше код работает с использованием Intel Fortran 12.1.0.

Ответы [ 2 ]

18 голосов
/ 25 ноября 2010

Возможно ли в настоящее время переопределить конструктор структуры в Fortran?

Нет. В любом случае, даже если вы используете ваш подход, это вовсе не переопределение конструктора. Основная причина в том, что структура конструктора # ООП конструктор. Есть некоторое сходство, но это просто другая идея.

Вы не можете использовать вашу не встроенную функцию в выражении инициализации. Вы можете использовать только конструктор констант, массивов или структур, встроенные функции, ... Для получения дополнительной информации взгляните на 7.1.7 Выражение инициализации в черновике Fortran 2003.

Принимая во внимание этот факт, я совершенно не понимаю, в чем реальная разница между

type(mytype) :: x
x = mytype(0)

и

type(mytype) :: x
x = init_mytype(0)

и в чем смысл использования блока INTERFACE в модуле mymod.

Ну, честно говоря, есть разница, огромная - первый путь вводит в заблуждение. Эта функция не является конструктором (поскольку в Фортране вообще нет конструкторов ООП), она является инициализатором.


В основном ООП конструктор отвечает за последовательное выполнение двух вещей:

  1. Распределение памяти.
  2. Инициализация элемента.

Давайте рассмотрим несколько примеров создания классов на разных языках.

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 ... Я не могу найти ее.

6 голосов
/ 24 ноября 2010

Я ознакомился со своей копией стандарта Fortran 2008.Это позволяет вам определять универсальный интерфейс с тем же именем, что и производный тип.Мой компилятор (Intel Fortran 11.1) не будет компилировать код, поэтому я подозреваю (без копии стандарта 2003 года), что это пока не реализованная функция стандарта Fortran 2003.

Кроме того, в вашей программе есть ошибка.Объявление вашей функции:

  type(mytype) function init_mytype
    integer, intent(in) :: i

указывает на существование и намерение аргумента, которого нет в спецификации функции, который, возможно, следует переписать как:

  type(mytype) function init_mytype(i)
...