2010-11-23 3 views
14

Est-il actuellement possible de surcharger le constructeur de structure dans Fortran? Je l'ai vu des exemples proposés comme celui-ci (par exemple dans la spécification 2003 Fortran):Comment remplacer un constructeur de structure dans fortran

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 

Cela génère essentiellement un tas d'erreurs dues à redondants noms de variables (par exemple erreur: attribut DÉRIVÉS des conflits « MyType » avec attribut PROCEDURE à 1)). Une copie textuelle de l'exemple fortran 2003 génère des erreurs similaires. J'ai essayé ceci dans gfortran 4.4, ifort 10.1 et 11.1 et ils produisent tous les mêmes erreurs.

Ma question: est-ce juste une fonctionnalité non implémentée de Fortran 2003? Ou est-ce que je l'applique incorrectement? Editer: J'ai rencontré un bug report et un announced patch à gfortran concernant ce problème. Cependant, j'ai essayé d'utiliser une version de novembre de gcc46 sans chance et avec des erreurs similaires.

Édition 2: Le code ci-dessus semble fonctionner avec Intel Fortran 12.1.0.

Répondre

6

J'ai consulté ma copie de la norme Fortran 2008. Cela vous permet de définir une interface générique avec le même nom qu'un type dérivé. Mon compilateur (Intel Fortran 11.1) ne compilera pas le code, donc je suis en train de soupçonner (sans une copie de la norme 2003 à la main) qu'il s'agit d'une fonctionnalité encore non implémentée de la norme Fortran 2003. En outre, une erreur est survenue dans votre programme. En outre, il y a une erreur dans votre programme. Votre déclaration de fonction:

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

précise l'existence et à l'intention d'un argument qui ne figure pas dans la spécification de la fonction, ce qui devrait peut-être réécrite comme:

type(mytype) function init_mytype(i) 
+0

merci, fixé. Toutes mes excuses pour l'erreur distrayante, c'était un exemple précipité. –

17

Is it currently possible to override the structure constructor in Fortran?

No. Quoi qu'il en soit même en utilisant votre approche n'est pas complètement sur le constructeur surchargé. La raison principale est ce constructeur de structure # OOP constructeur. Il y a une certaine similitude mais c'est juste une autre idée.

Vous ne pouvez pas utiliser votre fonction non intrinsèque dans l'expression d'initialisation. Vous pouvez utiliser uniquement un constructeur de constante, de tableau ou de structure, des fonctions intrinsèques, ... Pour plus d'informations, jetez un oeil à 7.1.7 Expression d'initialisation dans le brouillon de Fortran 2003.

Prenant compte de ce fait, je complètement ne comprends pas quelle est la différence réelle entre

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

et

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

et quel est le point entier d'utiliser le bloc d'interface interne mymod MODULE.

Eh bien, honnêtement, il y a une différence, l'énorme - la première est trompeuse. Cette fonction n'est pas le constructeur (car il n'y a aucun constructeur OOP dans Fortran), c'est un initialiseur.


dans le constructeur POO grand public est responsable de faire successivement deux choses:

  1. allocation de mémoire.
  2. Initialisation de membre. Jetons un coup d'oeil à quelques exemples d'instanciation de classes dans des langues différentes.

Dans Java:

MyType mt = new MyType(1); 

un fait très important est caché - le fait que l'objet est en fait un pointeur vers une varibale d'un type de classe. L'équivalent en C++ sera allocation sur tas utilisant:

MyType* mt = new MyType(1); 

Mais dans les deux langues, on peut voir que deux fonctions de constructeur se reflètent même au niveau de la syntaxe. Il se compose de deux parties: mot-clé new (allocation) et nom du constructeur (initialisation). Dans Objective-C syntaxe est encore plus insisté sur ce fait:

MyType* mt = [[MyType alloc] init:1]; 

Plusieurs fois, cependant, vous pouvez voir une autre forme d'invocation du constructeur. Dans le cas de l'allocation sur pile C++ utilise la construction de syntaxe spéciale (très pauvres)

MyType mt(1); 

qui est en fait trompeur que nous ne pouvons tout simplement pas le considérer.

Dans Python

mt = MyType(1) 

à la fois le fait que l'objet est en fait un pointeur et le fait que ont lieu d'affectation d'abord sont cachés (au niveau de la syntaxe). Et cette méthode est appelée ... __init__! O_O Donc, c'est trompeur. L'allocation de pile С ++ s'estompe par rapport à celle-là. =)


Quoi qu'il en soit, l'idée d'avoir constructeur dans la langue implique la possibilité de faire l'allocation une initialisation dans une instruction à l'aide de la méthode une sorte spéciale. Et si vous pensez que c'est "vrai OOP", j'ai de mauvaises nouvelles pour vous. Même Smalltalkdoesn't have constructors. C'est juste une convention d'avoir une méthode new sur les classes elles-mêmes (ce sont des objets singleton de méta-classes). Le Factory Design Pattern est utilisé dans de nombreuses autres langues pour atteindre le même objectif.

J'ai lu quelque part que les concepts de modules dans Fortran étaient inspirés par Modula-2. Et il semble pour moi que les fonctionnalités OOP sont inspirées par Oberon-2. Il n'y a pas non plus de constructeurs à Oberon-2. Mais il y a bien sûr une allocation pure avec une procédure pré-déclarée NEW (comme ALLOCATE dans Fortran, mais ALLOCATE est une déclaration). Après l'allocation, vous pouvez (en pratique) appeler un initialiseur, qui est juste une méthode ordinaire. Rien de spécial là-bas.

Vous pouvez donc utiliser une sorte d'usine pour initialiser des objets. C'est ce que vous avez réellement fait en utilisant des modules au lieu d'objets singleton. Ou il est préférable de dire qu'ils (programmeurs Java/C#/...) utilisent des méthodes objets singleton au lieu de fonctions ordinaires en raison de l'absence de la dernière (pas de modules - pas moyen d'avoir des fonctions ordinaires, seulement des méthodes).

Vous pouvez également utiliser SUBROUTINE lié au type à la place.

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) pour this arg de init SUBROUTINE semble bien. Parce que nous attendons que cette méthode soit appelée seulement une fois et juste après l'allocation. Cela pourrait être une bonne idée de contrôler que cette hypothèse ne sera pas fausse. Pour ajouter un drapeau booléen LOGICAL :: inited à mytype, vérifiez s'il est .false. et réglez-le sur .true. lors de la première initialisation, et faites autre chose lors de la tentative de réinitialisation. Je me souviens certainement de quelque chose à ce sujet dans Google Groupes ... Je ne le trouve pas.

+2

Merci pour la clarification. Je comprends que ce n'est pas un constructeur au sens propre de la POO, et que des approches alternatives similaires accompliront presque la même chose. Il s'agit plutôt d'un exemple presque in extenso de p445 (C.1.6) que les auteurs ont choisi d'appeler un «constructeur de structure» dans l'un des brouillons de travail de spécification. Je me demandais si une telle dérogation était actuellement possible dans les implémentations communes de fortran. Mais je vais prendre vos conseils à cœur, merci encore. –

Questions connexes