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

 Delphi Discussion :

Quand utiliser Inherited 'Ma procedure" ou inherited tout court


Sujet :

Delphi

  1. #21
    Expert confirmé

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Leader Technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Points : 4 170
    Points
    4 170
    Par défaut
    Citation Envoyé par peter27x Voir le message
    J'ai lu toutes vos réponse, suis allé chercher des infos dans le F1 de Delphi, mais je vois tjrs pas clair dans tout ça... Je trouve que ça manque d'explications simples et claires.

    Il y a 5 "types" de methodes de classe en Delphi:

    Statique
    Dynamique
    Dynamique abstraite
    Virtuelle
    Virtuelle abstraite
    En fait, si tu les classes comme ça, il y en a un peu plus que 5 :

    Les méthodes de classes : Celles qu'on définit avec class procedure ou class function. Il s'agit de méthodes qui peuvent être appellée indépendemment de toutes instances de la classe. Lorsque tu les appelles, tu indique le type de la classe, ainsi que le nom de la méthode. Comme il n'y a pas d'instance associée, ces méthodes ne peuvent pas accéder aux attributs de l'objet (sauf s'il s'agit également de variables de classes). Ces méthodes possède cependant un paramètre Self implicite qui désigne le type de la classe à partir duquel elles sont appellés (Ca doit sûrement avoir une utilité...)

    Les méthodes static : Comme pour les méthodes de classe, sauf qu'elles ne possèdent pas de paramètres self implicite. Il est donc possible de les utiliser comme méthode callback lorsqu'on travaille avec certaines API Win32. En fait, on peut aussi les voir commes des procédures et fonctions ordinaires qu'on déclare à l'intérieur d'un objet pour la lisibilité du code.

    Dynamique ou Virtuelle : Comme ça a été expliquée précédemment les deux ne se distinguent que par leur implémentation internes. Personnellement, je passe tout en virtual et je ne me pose pas de questions. Il s'agit des méthodes virtuelles classiques, c'est à dire une méthode dont on pourra redéfinir l'implémentation dans une classe dérivée.

    Les méthodes abstraites : Une méthode abstraite et une méthode qui est déclarée dans la base de base, mais pour laquelle on ne peut pas (ou on ne veut pas) fournir d'implémentation. Et surtout, on veut forcer le développeur à la redéfinir dans les classes dérivées. Lorsqu'on déclare une méthode comme étant abstraite, on ne définit plus d'implémentation associée.
    De facto, une méthode abstraite doit nécessairement être virtuelle. Dans Delphi, on définit un méthode abstraite en ajoutant le mot-clé "abstract" après la définition de la méthode virtuelle. Comme on a deux type de méthode virtuelle, on obtient "dynamique abstraite" et "virtuelle abstraite".

    Il y a aussi les méthodes "normal", celle que tu appelles "Statique". Elles ont accès aux attribut de l'instance. Les classes dérivées peuvent y faire appel. Par contre, elles ne peuvent pas être surchargées.

    On pourrait encore ajouter à celà les procédures de message et les méthodes publiées...

    On a de la chance, en Delphi Win32, on ne peut pas encore déclarer de méthode Final (qui étaient virtuelle, mais qu'on décide de sceller dans une classe et qui ne pourront plus être surchargées dans les classes dérivées).

    Je sais ce n'est pas toujours très facile à suivre. Delphi possède beaucoup de concepts qui lui sont propres, liés à l'implémentation du RAD et qui ne font pas partie de la "norme objet"

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 693
    Points : 13 128
    Points
    13 128
    Par défaut
    Je vois pas le lien entre, d'une part le type de déclaration parmis les 5 types cités plus haut, et d'autre part, les manières autorisées ou pas de la "récupérer" chez les enfants...
    Le enfants pourront toujours y accéder. Le sujet tourne trop autour de l'héritage, du codage. Il y a une phrase qui ressort de plusieurs posts:

    les méthodes virtuelles constituent la manière la plus efficace d'implémenter un comportement polymorphique.
    Dans le sens où il ne faut pas seulement réfléchir si la dernière sous classe doit appeler les procédures des classes héritées mais d'avoir à l'exécution une variable d'une classe de base qui se comportera différement en fonction de la classe réelle assignée.

    Virtuel ou dynamique veut dire: Oui mon comportement peut être surchargé je doit regarder plus bas (sinon je m'arrête là).

    Override veut dire: Oui je te surcharge, exécutes-moi ! (sinon ignores-moi, et mes sous classes avec)

    Quant à l'Inherited, c'est une façon simple de faire référence à la même procédure de la classe héritée, mais n'a finalement pas grand chose à voir avec l'héritage en lui-même.

  3. #23
    Membre confirmé
    Avatar de Jcpan
    Inscrit en
    Août 2008
    Messages
    542
    Détails du profil
    Informations forums :
    Inscription : Août 2008
    Messages : 542
    Points : 475
    Points
    475
    Par défaut
    Citation Envoyé par Franck SORIANO Voir le message

    On pourrait encore ajouter à celà les procédures de message et les méthodes publiées...
    Pouvez-vous expliquer d'avantage les lignes précédente ?
    Merci

  4. #24
    Membre éclairé Avatar de peter27x
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 029
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 029
    Points : 757
    Points
    757
    Par défaut
    Merci BCP Franck SORIANNO !!!

    C'est clair et limpide.

  5. #25
    Membre éclairé Avatar de peter27x
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 029
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 029
    Points : 757
    Points
    757
    Par défaut
    Citation Envoyé par Andnotor Voir le message
    Override veut dire: Oui je te surcharge, exécutes-moi ! (sinon ignores-moi, et mes sous classes avec)
    Que signifie exactement le "(sinon ignores-moi, et mes sous classes avec)" ?

    Merci.

  6. #26
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 445
    Points
    28 445
    Par défaut
    si je puis me permettre une explication simple

    un objet c'est au départ comme un RECORD, une série de champs.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    type
     TMonRecord=record
       a,b,c:integer;
     end;
     TMonObject=class
      a,b,c:integer;
     end;
    la seule grosse différence c'est que l'objet est alloué lors du Create alors que le record est statique.

    une méthode (statique) c'est une procédure qui possède un paramètre implicite SELF qui pointe sur la liste des champs de l'objet.

    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
     
    type
     TMonRecord=record
       a,b,c:integer;
     end;
     
     TMonObject=class
      a,b,c:integer;
      procedure maMethode;
     end;
     
    procedure TMonObject.maMethode;
    begin
      Self.a:=1;
    end;
     
    procedure maProcedure(var Self:TMonRecord);
    begin
      Self.a:=1;
    end;
    la petite nuance étant qu'il n'est pas nécessaire sous Delphi de préciser "Self." pour accéder à un champ de l'objet.

    On en arrive aux méthodes virtuelles : c'est un pointeur vers une méthode, il peut donc changer d'un objet à ses dérivés :

    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
     
    type
     TMonRecord=record
       a,b,c:integer;
       maProcedure2:procedure(var Self:TMonRecord);
     end;
     
     TMonObject=class
      a,b,c:integer;
      procedure maMethode;
      procedure maMethode2; virtual;
     end;
     
    procedure TMonObject.maMethode;
    begin
      Self.a:=1;
    end;
     
    procedure TMonObject.maMethode2;
    begin
      Self.b:=2;
    end;
     
    procedure maProcedure(var Self:TMonRecord);
    begin
      Self.a:=1;
    end;
     
    procedure maProcedure2_Version1(var Self:TMonRecord);
    begin
      Self.b:=2;
    end;
     
    procedure CreateMonRecord(var Self:TMonRecord);
    begin
      Self.maProcedure2:=maProcedure2_Version1;
    end;
    j'ai ajouté ici un simili constructor pour MonRecord qui va renseigner Self.maProcedure2 ... c'est ce que fera le constructor de TMonObject avec sa VMT (Table de Méthodes Virtuelles) pour la faire pointer sur la méthode MaMethode2.

    quand on crée un classe dérivée de TMonObject et qu'on redéclare cette méthode avec le mot clé override, on vient remplacer dans la VMT l'adresse de la méthode virtuelle par sa nouvelle version...du coup, un appel à la méthode invoque un code différent...comme avec le code ci-dessous :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    procedure maProcedure2_Version2(var Self:TMonRecord);
    begin
      Self.b:=3;
    end;
     
    procedure CreateMonRecord2(var Self:TMonRecord);
    begin
      Self.maProcedure2:=maProcedure2_Version2;
    end;
    depuis quelques version de Delphi est apparu le mot clé reintroduce qui précise que la nouvelle version de la méthode porte le même nom que l'ancienne, mais ne la remplace pas !
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 693
    Points : 13 128
    Points
    13 128
    Par défaut
    Prenons 2 cas (en simplifiant l'écriture ) avec une variable de type TClass1:

    TClass1 Proc virtuel
    TClass2 Proc override
    TClass3 Proc override
    TClass4 Proc override

    A l'appel de Proc sur cette variable, le traitement commencera à TClass4 puisque toutes les méthodes héritées sont override.

    TClass1 Proc virtuel
    TClass2 Proc override
    TClass3 Proc
    TClass4 Proc override

    Cette fois, le traitement commencera à TClass2 puisque le chaînage est rompu. Même si l'objet réel est bien du type TClass4, notre variable est de type TClass1.

  8. #28
    Expert confirmé

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Leader Technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Points : 4 170
    Points
    4 170
    Par défaut
    Citation Envoyé par Jcpan Voir le message
    Pouvez-vous expliquer d'avantage les lignes précédente ?
    Merci
    Les méthodes de message, c'est qu'on déclare avec la directive message + n° de message n'ont rien à voir avec les concepts OO.

    Il s'agit d'un raccourcit introduit dans la syntaxe Delphi pour s'éviter de surcharger explicitement la procédure de message de contrôle fenêtrés sous windows :
    Normalement, dans la programmation Windows, chaque "composant" visuel est une "fenêtre" au sens windows. A cette époque, la programmation objet et les interfaces n'existaient pas. La communication entre deux fenêtres se fait à coup d'envoie de messages.
    Lorsque tu crée un nouveau composant, tu crée en fait une fenêtre personnalisée à laquelle tu associes une procédure de fenêtre.
    Lorsque les messages windows de l'application sont dispatchés à leur fenêtre destinataire, la procédure de message est appelée et elle reçoit un le message windows en paramètre.
    Normalement, cette procédure fait un gros case n° message of, pour faire le traitement voulu en fonction du message. Tous les messages windows passent par cette procédure de message et ils sont vraiment très nombreux.
    Pour simplifier l'écriture et la surcharge de ces messages, Delphi a introduit les méthodes pour chaque message windows que tu veux traiter. Et tu indiques le numéro du message que tu veux intercepter. La VCL se chargera alors d'appeler ta procédure automatiquement, chaque fois que le message demandé sera reçu.

    Les méthodes publiées sont différentes. Il s'agit de méthodes, nécessairement publiques et virtuelles qui peuvent être appelées par "Reflexion", uniquement à partir de leur nom, sans connaitre quoi que ce soit de l'objet qui l'implémente.
    Elles ont été introduites dans Delphi, pour permettre à la VCL de gérer le streaming avec les DFM.
    Lors du chargement d'une fiche, son constructeur est d'abord appelé : Tous les composants déposés sur la fiche sont créés, mais ils ignorent les valeurs des propriétés qui ont été définies en design. Ces dernières sont lues par un traitement générique à partir du DFM. Lorsque le DFM est lu, la VCL obtient un nom de composant, un nom de propriété et une valeur (qui peut être le nom d'une méthode pour les événements).
    Elle doit alors se débrouiller dynamiquement pour retrouver le composant qui porte ce nom, retrouver la propriété et les méthodes qui portent les noms du DFM.
    C'est ce que permettent de faire les méthodes publiées : Pour ces dernières, le compilateur gère des informations de types qu'il est possible d'interroger au runtime les fameuses RTTI.

  9. #29
    Membre confirmé
    Avatar de Jcpan
    Inscrit en
    Août 2008
    Messages
    542
    Détails du profil
    Informations forums :
    Inscription : Août 2008
    Messages : 542
    Points : 475
    Points
    475
    Par défaut
    ainsi comment expliquer ce cas ??

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Inherited Ma procedure as Montype

  10. #30
    Membre chevronné

    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    1 519
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 1 519
    Points : 2 153
    Points
    2 153
    Billets dans le blog
    1
    Par défaut
    Jamais vu ce cas de figure et il me semble improbable. En effet puisque c'est une procédure, on ne peut pas caster sa valeur de retour puisqu'elle n'en a pas.

    Montre un exemple concret de code avec cette écriture.
    La FAQ - les Tutoriels - Le guide du développeur Delphi devant un problème

    Pas de sollicitations techniques par MP -

  11. #31
    Membre confirmé
    Avatar de Jcpan
    Inscrit en
    Août 2008
    Messages
    542
    Détails du profil
    Informations forums :
    Inscription : Août 2008
    Messages : 542
    Points : 475
    Points
    475
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
     
    function TMaclasse.Construire : TVoiture;
    begin
     Result  := inherited Construire  as TVoiture;
    end
    ;

  12. #32
    Membre chevronné

    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    1 519
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 1 519
    Points : 2 153
    Points
    2 153
    Billets dans le blog
    1
    Par défaut
    Ok donc c'était pas une procédure.

    Maintenant il nous faudrait un peu plus de détails à savoir la déclaration TMaclasse.Construire ainsi que la déclaration dans la classe de base.
    La FAQ - les Tutoriels - Le guide du développeur Delphi devant un problème

    Pas de sollicitations techniques par MP -

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 693
    Points : 13 128
    Points
    13 128
    Par défaut
    Sans avoir testé, cela me paraît impossible.

    Soit il y a héritage et le transtypage est inutile, soit la fonction est redéfinie (pas d'override) et l'inherited ne peut plus être utilisé.

    Ne confondrais-tu pas avec un appel comme celui-ci ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    function TMaclasse.Construire : TVoiture;
    begin
     Result := TMaClasseDeBase(Self).Construire as TVoiture;
    end;

  14. #34
    Membre confirmé
    Avatar de Jcpan
    Inscrit en
    Août 2008
    Messages
    542
    Détails du profil
    Informations forums :
    Inscription : Août 2008
    Messages : 542
    Points : 475
    Points
    475
    Par défaut
    Non la fonction est comme je l'ai donné

  15. #35
    Membre chevronné

    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    1 519
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 1 519
    Points : 2 153
    Points
    2 153
    Billets dans le blog
    1
    Par défaut
    Je ne vois que deux cas de figure où c'est possible, soit :

    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
    type
      TBaseClass = class
      protected
        function MaProc: TObject; virtual;
      end;
     
      TMaClass = class( TBaseClass )
      protected
        function MaProc: TObject; override;
      end;
     
    implementation
     
    function TBaseClass.MaProc: TObject;
    begin
      Result := TObject.Create;
    end;
     
    function TMaClass.MaProc: TObject;
    begin
      Result := inherited MaProc as TObject;
    end;
    Mais là c'est redondant et donc inutile. Ou bien :

    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
    type
      TBaseClass = class
      protected
        function MaProc: TObject;
      end;
     
      TMaClass = class( TBaseClass )
      protected
        function MaProc: TMaClass;
      end;
     
    implementation
     
    function TBaseClass.MaProc: TObject;
    begin
      Result := TObject.Create;
    end;
     
    function TMaClass.MaProc: TMaClass;
    begin
      Result := inherited MaProc as TMaClass;
    end;
    Ce cas est justement celui où tu n'utilises pas le concept de polymorphisme mais que tu forces une méthode a prendre la place de celle de la classe de base. Néanmoins dans la méthode de la classe tu peux faire appel à la méthode définie dans la classe père directe que tu peux éventuellement caster si cela t'arrange.
    La FAQ - les Tutoriels - Le guide du développeur Delphi devant un problème

    Pas de sollicitations techniques par MP -

Discussions similaires

  1. [MySQL 5.0] RAND() inefficace quand utilisation de GROUP BY
    Par Takusen dans le forum Langage SQL
    Réponses: 2
    Dernier message: 05/11/2006, 15h39
  2. [POO] Quand utiliser une classe ?
    Par Gwipi dans le forum Langage
    Réponses: 8
    Dernier message: 05/05/2006, 14h31
  3. Réponses: 10
    Dernier message: 08/02/2005, 10h52
  4. Écriture dans un DBgrid quand utilise un query comme dataset
    Par dcayou dans le forum Bases de données
    Réponses: 3
    Dernier message: 13/07/2004, 22h22
  5. [Procédure Stocké] Quand utiliser ?
    Par touhami dans le forum Bases de données
    Réponses: 2
    Dernier message: 18/03/2004, 09h09

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