Как переопределить конструктор конструктора в Фортране

StackOverflow https://stackoverflow.com/questions/4262253

Вопрос

В настоящее время можно переопределить конструктор конструктора в 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), это инициализатор.


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

  1. Выделение памяти.
  2. Инициализация участника.

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

В Джава:

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top