2016-03-16 7 views
1

Я довольно новичок в Fortran OOP, и перед инициализацией родительских и производных типов я столкнулся с некоторыми проблемами. У меня есть один модуль, содержащий родительский тип object (извините за чрезмерное использование слова ..) и его производный тип circle, у которого есть дополнительное поле radius.Производные типы и конструкции расширенного типа

Способ, которым мне нужно инициализировать тип object, теперь требует использования фиктивного аргумента радиуса, которого я бы хотел избежать. Итак, на данный момент у меня есть работы, но я хотел бы знать, как это сделать, так как это не кажется очень практичным, если мне нужно будет иметь дополнительные производные типы от object в будущем.

Я думаю, что использование в качестве абстрактного родительского типа object поможет в этом смысле? Или используя общие процедуры, но я действительно не знаю, как это сделать.

Код приведен ниже.

module objectMod 
    implicit none 

    type :: object 
    real,allocatable :: x(:,:)   ! position vector (points) --- (M,{i,j}) 
    real    :: centre(2)  ! centre of the object 
    integer   :: M=50    ! number of Lagrangian points of the object (default) 
    real    :: eps=0.1   ! kernel of the surface (default) 
    contains 
    procedure :: init=>init_object 
    end type object 

contains 

    subroutine init_object(a,centre,radius,M,eps) 
    implicit none 

    class(object),intent(inout) :: a 
    real,intent(in)    :: centre(2) 
    integer,intent(in),optional :: M 
    real,intent(in),optional  :: eps 
    real,intent(in),optional  :: radius ! ignored for object 

    if(present(M)) a%M = M 
    if(.not.allocated(a%x)) allocate(a%x(a%M,2)) 
    a%centre = centre 
    if(present(eps)) a%eps = eps 
    end subroutine init_object 
end module objectMod 

module geomMod 
    use objectMod 
    implicit none 
    real,parameter :: PI = 3.14159265 

    type,extends(object) :: circle 
    real    :: radius ! radius 
    contains 
    procedure :: init=>init_circle 
    end type circle 

contains 

    subroutine init_circle(a,centre,radius,M,eps) 
    implicit none 
    class(circle),intent(inout) :: a 
    real,intent(in)    :: centre(2) 
    real,intent(in),optional :: radius 
    integer,intent(in),optional :: M 
    real,intent(in),optional :: eps 

    integer :: i 
    real :: dtheta 

    ! object type attributes initialization 
    a%centre = centre 
    if(present(M)) a%M = M 
    if(.not.allocated(a%x)) allocate(a%x(a%M,2)) 
    if(present(eps)) a%eps = eps 
    ! circle type attributes initialization 
    a%radius = radius 

    dtheta = 2.*PI/real(a%M-1) 
    do i = 1,a%M 
     a%x(i,1) = a%radius*cos(dtheta*(i-1))+a%centre(1) 
     a%x(i,2) = a%radius*sin(dtheta*(i-1))+a%centre(2) 
    end do 
    end subroutine init_circle 
end module geomMod 
+0

Я не могу сбросить радиус, потому что тогда я получаю ошибку несоответствия аргументов (очевидно, я пробовал это). По fancier я имею в виду способ не нуждаться в фиктивных аргументах для родительского конструктора, поскольку он станет неприятным, поскольку я добавляю все больше и больше расширенных типов «объекта». И иногда мне нужно создать экземпляр «объекта». –

+0

Я действительно использовал этот источник, чтобы закодировать это. Поиск там «проигнорирован для формы», поскольку это часть кода, который я фактически использую, и который требует использования фиктивных аргументов для родительских типов. –

ответ

0

Ошибка, которую вы делаете, заключается в том, чтобы создавать конструкторы как процедуры с привязкой к типу. Требование, чтобы список аргументов соответствовал, противоречит вам.

Процедуры с привязкой к строкам - это просто не подходящий инструмент для конструкторов (или инициализаторов).

В Fortran мы используем функции, возвращающие экземпляр объекта для его инициализации.

function init_object(centre,M,eps) result(a) 
    type(object) :: a 
    real,intent(in)    :: centre(2) 
    integer,intent(in),optional :: M 
    real,intent(in),optional  :: eps 
    !NO radius 
end function init_object 


interface object 
    procedure init_object 
end interface 



.... 



obj = object(my_centre, my_m, my_eps) 

Это также, как вызываются конструкторы структуры по умолчанию.


Я вижу, что вы взяли пример из некоторого онлайн-учебника. Я считаю, что этот пример плохой. Если вы не согласны, вам придется жить с этими проблемами, которые он приносит.


Так, в принципе, вы хотите метод инициализации вместо конструктора (см Why use an initialization method instead of a constructor? для некоторого обсуждения. Objective-C использует что-то подобное https://www.binpress.com/tutorial/objectivec-lesson-11-object-initialization/76 но более поздний Swift использует конструкторы вместо этого.).

Вы можете использовать дженерики таким образом:

module types 

     type t1 
      integer :: i 
     contains 
      generic :: init => init_t1 
      procedure, private :: init_t1 
     end type 

     type, extends(t1) :: t2 
      integer :: j 
     contains 
      generic :: init => init_t2 
      procedure, private :: init_t2 
     end type 

     type, extends(t2) :: t3 
      integer :: k 
     contains 
      generic :: init => init_t3 
      procedure, private :: init_t3 
     end type 

    contains 


     subroutine init_t1(self, i) 
     class(t1) :: self 
     end subroutine 

     subroutine init_t2(self, i, j) 
     class(t2) :: self 
     end subroutine 

     subroutine init_t3(self, i, j, k) 
     class(t3) :: self 
     end subroutine 

    end module 

На мой взгляд, это некрасиво и не по-Fortranic, но это не то, что вы хотите.

Вам нужно будет особо заботиться о том, чтобы пользователь не вызывал неправильную версию непреднамеренно, перегружая ее тем, что выдаст сообщение об ошибке.

Мой совет по-прежнему заключается в том, чтобы скорее следовать общим шаблонам, а не изобретать собственные способы, которые смутят тех, кто привык к мейнстриму.

+0

Спасибо за ваш ответ @ Vladimir-F.Я хотел бы, чтобы они были связаны с привязкой к типу процедур, поэтому я думаю, что лучше всего было бы установить «объект» как абстрактный родительский тип. Но тогда я не смогу использовать «объект» в главной программе, верно? –

+0

Я не вижу причины абстрактного типа. И определенно нет причин, которые имели бы какую-либо связь с моим ответом. Пожалуйста, прочитайте его снова * «Если вы действительно хотите использовать процедуры с привязкой к типу в любом случае, вы можете, но у вас не может быть одного универсального% init(), вы должны использовать другое имя для каждого типа и, вероятно, -overridable. "* –

+0

Кстати, я могу попросить причину, чтобы они были связаны с привязкой к типу? Я не могу найти. Помните, что в Java или C++ или аналогичные люди также используют функции, которые возвращают объект (или ссылку на него). –