IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Delphi Discussion :

Héritage: comment faire appel à une fonction d'une sous classe


Sujet :

Langage Delphi

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2008
    Messages : 6
    Points : 2
    Points
    2
    Par défaut Héritage: comment faire appel à une fonction d'une sous classe
    Bonjour,

    Est il possible de faire la chose suivante? Si oui, pourriez vous me donner des pistes?

    Mise en situation : j'ai plusieurs programmes où j'ai une fenêtre simillaire, pour faire des choses différentes, mais elles sont toutes fort proche d'un point de vue graphique et au niveau du fonctionnement, les grandes lignes sont simillaires, il y a juste dans certaines un peu plus de traitement que dans d'autres.

    L'idée est de faire une fenêtre générique liée à un Datamodule générique que j'incluerais dans chaque projet puis, créer une fiche et un datamodule qui héritent de ceux générique. Enfin, dans les classes dérivées, je détaillerais les traitements spécifiques à réaliser.

    J'ai donc créé à l'intérieur d'un nouveau projet reprennant ce type de fenêtre une fenêtre et un datamodule qui se veulent générique et j'ai créé une fiche et un datamodule qui en hérite.

    Voici le contenu agrégé d'une des fonction de la "super" fiche, la classe mère:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
      procedure TSelectFrm.SelectObjet(Id_Personne, Id_Objet, application_name: String;
        SelAction: TObjetSelAction);
      begin
        With SelectXPersDM do
        begin
          // Fournit les requêtes derrière le dbGrid et PersQry
          SetSql_Qry(application_name);
          //Si nécessaire: manipule les données de DBGridProviderQry et effectue le changement de DataSet
          Manipulation_Data(application_name);
          // Fait le lien entre les colonnes du DBGrid et les champs du Datasource
          //  ConstructionDBGrid
        end;
      end;
    Manipulation_Data est implémentée dans le datamodule générique

    Voici son code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    procedure TSelectXPersDM.Manipulation_Data(application_name: String);
    begin
      case AnsiIndexStr(application_name, ['Application_A', 'Application_B', 'Application_C']) of
        0 :
        begin
          Manipulation_Data_Application_A;
        end;
        1 : 
        begin
          Manipulation_Data_Application_B;
        end;
        2 : 
        begin
          Manipulation_Data_Application_C;
        end;
      end;
    end;
    J'ai déclaré les procédures de type Manipulation_Data_X comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
      protected
        { Déclarations protected }
        procedure Manipulation_Data_A; virtual; abstract;
        procedure Manipulation_Data_B; virtual; abstract;
        procedure Manipulation_Data_C; virtual; abstract;
    L'idée est bien sur que les procédure de type Manipulation_Data_Application_X soit implémentée dans le datamodule (qui hérite du datamodule générique) de l'application X.

    Aussi, dans le datamodule qui hérite de celui générique, j'ai déclaré la procédure de cette manière :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
      public
        { Déclarations publiques }
        procedure Manipulation_Data_A; override ;
      end;
    Et là, j'ai un problème pour organiser tout cela.
    En suivant pas à pas dans le code, je passe bien par les fonctions génériques mais une fois dedans, je ne sais pas comment faire pour faire appel à des fonctions plus spécifique définie dans la sous classe ( le datamodule qui hérite ).

    C'est la première fois que j'essaye de faire ce type de chose (créer une fenêtre générique destinée à être héritée afin de compléter certains traitement), il s'agit là d'un test.

    Pouvez vous me conseillez sur la manière de faire?

    Merci
    Seb7710

  2. #2
    Membre éclairé Avatar de Kaféine
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 569
    Points : 736
    Points
    736
    Par défaut
    Salut,

    J'ai l'impression que tu t'en ai bien sortie...

    En suivant pas à pas dans le code, je passe bien par les fonctions génériques mais une fois dedans, je ne sais pas comment faire pour faire appel à des fonctions plus spécifique définie dans la sous classe ( le datamodule qui hérite )
    si c'est spécifique c'est plus générique :\

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    procedure Manipulation_Data_A; override ;
    dans cette procedure du descendant, rien n'empeche d'appeler des méthodes spécifique du descendant non?

    Je ne vois pas le problème?...
    Akim Merabet

  3. #3
    Membre éprouvé Avatar de Yurck
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2005
    Messages
    682
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 14
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2005
    Messages : 682
    Points : 912
    Points
    912
    Par défaut
    Citation Envoyé par Kaféine Voir le message
    J'ai l'impression que tu t'en ai bien sortie...
    Je ne suis pas de cet avis.

    J'ai l'impression que ta logique est inversée.
    En effet dans le datamodule père tu n'a pas à appeler les procédures du descendant elles le sont automatiquement puisqu'elles sont redéclarées dans celui-ci.
    Dans le vocabulaire des couturiers seulement, patron est synonyme de modèle.
    Aymond d'Alost

  4. #4
    Membre éprouvé Avatar de Yurck
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2005
    Messages
    682
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 14
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2005
    Messages : 682
    Points : 912
    Points
    912
    Par défaut
    Ton code devrais plutôt avoir cette forme

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     
     
    TDataManipulation = class(tDatamodule)
    protected
        { Déclarations protected }
        procedure Manipulation_Data; virtual;
    end;
     
     
    TDataManipulation_A = class(TDataManipulation)
    protected
        { Déclarations protected }
        procedure Manipulation_Data; override;
    end;
     
    TDataManipulation_B = class(TDataManipulation)
    protected
        { Déclarations protected }
        procedure Manipulation_Data; override;
    end;
     
    TDataManipulation_C = class(TDataManipulation)
    protected
        { Déclarations protected }
        procedure Manipulation_Data; override;
    end;
    après en focntion de ce que tu veux ou non avoir un tronc commun à tes ces procédures alors tu déclares la première en virtual ou en overload pour pouvoir y effectuer un traitement qui sera rappeler ou pas par le inherited dans les enfants.
    Dans le vocabulaire des couturiers seulement, patron est synonyme de modèle.
    Aymond d'Alost

  5. #5
    Candidat au Club
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2008
    Messages : 6
    Points : 2
    Points
    2
    Par défaut
    Citation Envoyé par Kaféine Voir le message

    dans cette procedure du descendant, rien n'empeche d'appeler des méthodes spécifique du descendant non?

    Je ne vois pas le problème?...
    Le problème apparemment, c'est que j'ai déclaré dans la classe générique la méthode plus spécifique.
    Je l'ai déclaré virtual; afin de pouvoir la surcharger.
    Je l'ai déclaré abstract; afin de spécifier au programme que j'allais l'implémenter dans la sous classe et non dans la classe générique.
    Le problème est que cela me produit une belle erreur EAbstractError avec le message 'Erreur abstraite' ....

    code où se produit l'erreur : (elle se produit lors de l'appel à manipulation_data_A)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    procedure TSelectXPersDM.Manipulation_Data(application_name: String);
    begin
      case AnsiIndexStr(application_name, ['Application_A', 'Chaîne2', 'Chaîne3']) of
        0 : // Utilisation par le programme A
        begin
          Manipulation_Data_A;
        end;
        1 : ; // Str = 'Chaîne2'
        2 : ; // Str = 'Chaîne3'
      end;
    end;

    Citation Envoyé par Yurck Voir le message
    Je ne suis pas de cet avis.

    J'ai l'impression que ta logique est inversée.
    En effet dans le datamodule père tu n'a pas à appeler les procédures du descendant elles le sont automatiquement puisqu'elles sont redéclarées dans celui-ci.
    Effectivement, je trouve aussi un peu bizzare comme pratique de faire appel appel dans la classe mère à une procédure implémentée dans la classe dérivée.

    Je vais continuer à cogiter sur le sujet, merci pour vos réactions.

    Il y a un problème actuellement avec le forum? Un message "Serveur surchargé" apparait très très souvent.

  6. #6
    Membre éclairé Avatar de Kaféine
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 569
    Points : 736
    Points
    736
    Par défaut
    Tout à fait d'accord avec toi Yurck dans ta vision.
    Mais en faite j'avais compris un truc plutôt comme ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
     
    TDMGenerique = class(TDataModule)
    protected
     procedure Manipulation_Data_A; virtual; abstract;
     procedure Manipulation_Data_B; virtual; abstract;
    public
     procedure Manipulation_Data(IsA: Boolean); 
    end;
     
    TDM_A = class(TDMGenerique)
    protected
     procedure Manipulation_Data_A; override;
     procedure Manipulation_Data_B; override;
    end;
     
    TDM_B = class(TDMGenerique)
    protected
     procedure Manipulation_Data_A; override;
     procedure Manipulation_Data_B; override;
    end;
     
     
    procedure TDMGenerique .Manipulation_Data(IsA: Boolean); 
    begin
     if IsA then Manipulation_Data_A
     else Manipulation_Data_B;
    end;

    ensuite je crée une instance de TDM_A et j'appelle Manipulation_Data(True) ou false. en fait le datamodule générique gère 2 algos de manipulation des datas, implémentés dans les descendants.

    Effectivement, je trouve aussi un peu bizzare comme pratique de faire appel appel dans la classe mère à une procédure implémentée dans la classe dérivée.
    l'idée de la méthode abstract c'est justement de pouvoir être appelée dans le Data module générique et l'implémentation est laissée à la charge des descendants ce qui peut être interessant des fois.
    Akim Merabet

  7. #7
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 671
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 671
    Points : 13 065
    Points
    13 065
    Par défaut
    Ton implémentation est parfaitement correct!

    Ton erreur doit plutôt venir de la création de ta variable.

    Si tu as un EAbstractError c'est que tu crée une variable de ton type générique et non du type hérité!

    Tu devrais avoir quelque chose du style:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    type
      TGeneric = class;
      TInherited = class(TGeneric);
     
    var
      MyVar :TGeneric;
     
    MyVar := TInherited.Create;
    ou si tu passes par une fonction:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    Type
      TGeneric = class;
      TInherited = class(TGeneric);
      TGenericClass = class of TGeneric;
     
    var
      MyVar :TGeneric;
     
    function Create_Inherited(aClass :TGenericClass) :TGeneric;
    begin
      Result := aClass.Create;
    end;
     
    MyVar := Create_Inherited(TInherited);
    Quant à l'Abstract, il oblige à être très strict dans l'implémentation du code Il est souvent plus judicieux d'avoir une procédure virtuel vide ou une fonction qui renvoi une valeur par défaut.

  8. #8
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 671
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 671
    Points : 13 065
    Points
    13 065
    Par défaut
    Pour être un peu plus précis
    Le code est juste mais l'exemple de Yurck est bien meilleur et respecte les bases de l'héritage et du polymorphisme Le test de ton application doit être fait avant la création de la variable.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    Type
      TGeneric = class;
      TInherited0 = class(TGeneric);
      TInherited1 = class(TGeneric);
     
    var
      MyVar :TGeneric;
     
    function CreateAppObject(aAppName :string) :TGeneric;
    begin
      case TonTest of
        0 : Result := TInherited0.Create;
        1 : Result := TInherited1.Create;
        else Raise Exception.Create('Application non-supportée!');
      end;
    end;
     
    MyVar := CreateAppObject(AppName);

Discussions similaires

  1. Appel d'une fonction dans une fonction d'une même classe
    Par script73 dans le forum Général Python
    Réponses: 3
    Dernier message: 06/03/2015, 11h18
  2. Faire appel à une fonction dans une fonction
    Par ThonySp dans le forum Scilab
    Réponses: 4
    Dernier message: 03/03/2015, 12h35
  3. Réponses: 1
    Dernier message: 10/12/2014, 16h11
  4. Appeler une fonction dans une fonction
    Par bryanstaubin dans le forum Macros et VBA Excel
    Réponses: 6
    Dernier message: 18/06/2007, 10h39
  5. Réponses: 1
    Dernier message: 12/09/2006, 15h44

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo