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 :

Problème d'héritage bizarre


Sujet :

Delphi

  1. #1
    Membre émérite
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    mars 2005
    Messages
    1 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : mars 2005
    Messages : 1 459
    Points : 2 626
    Points
    2 626
    Par défaut Problème d'héritage bizarre
    Bonjour,

    J'utilise Delphi 7.
    J'ai un comportement que je ne comprends pas dans l'utilisation et le passage d'un objet en paramètre.

    J'ai une classe TMinimalTradeAddress défini comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    TMinimalTradeAddress = class
    private
    public
      CountryId : String; // Code ISO pays (obligatoire)
    end;
    Je l’agrège à une classe TMinimalTradeParty
    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
    TMinimalTradeParty = class
    private
      FTradeAddress : TMinimalTradeAddress;
    public
      Name : String; // Nom (obligatoire)
     
      property TradeAddress : TMinimalTradeAddress read FTradeAddress; // Données de l'adresse
     
      constructor Create;
      destructor Destroy; override;
    end;
     
    constructor TMinimalTradeParty.Create;
    begin
      FTradeAddress := TMinimaTradeAddress.Create;
    end;
     
    destructor TMinimalTradeParty.Destroy;
    begin
      FreeAndNil(FTradeAddress);
      inherited;
    end;
    J'ai une classe TBasicTradeAddress héritant de TMinimalTradeAddress
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    TBasicTradeAddress = class(TMinimalTradeAddress)
    private
    public
      PostCode : String; // Code postal
      LineOne : String; // Adresse 1
      LineTwo : String; // Adresse 2
      LineThree : String; // Adresse 3
      CityName : String; // Ville
      CountrySubDivisionName : String; // Region
    end;
    Et une classe TBasicTradeParty héritant de TMinimalTradeParty et agrégeant un TBasicTradeAddress (héritant de TMinimalTradeAddress)
    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
    TBasicTradeParty = class(TMinimalTradeParty)
    private
      FTradeAddress : TBasicTradeAddress;
    public
      property TradeAddress : TBasicTradeAddress read FTradeAddress; // Données de l'adresse
     
      constructor Create;
      destructor Destroy; override;
    end;
     
    constructor TBasicHybridInvoiceTradeParty.Create;
    begin
      inherited Create;
     
      FTradeAddress := TBasicTradeAddress.Create;
    end;
     
    destructor TBasicTradeParty.Destroy;
    begin
      FreeAndNil(FTradeAddress);
      inherited;
    end;
    Mon problème se situe dans l'utilisation de ces classes et notamment dans les classes chargés de renseigner les données.
    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
    IMinimalDataCollector = interface
    ['{76C2E80F-CA36-48A6-87EF-DDDE2A7A44F6}']
      procedure FillTradeParty(TradeParty : TMinimalTradeParty); 
    end;
    
    IBasicHybridInvoiceDataCollector = interface(IMinimalDataCollector)
    ['{D4C43B05-58E5-40C4-87FA-4B0758C56633}']
      procedure FillTradePartyBasic(TradeParty : TBasicTradeParty);
    end;
    
    TMinimalDataCollector = class(TInterfacedObject, IMinimalDataCollector)
    private
    public
      procedure FillTradeParty(TradeParty : TMinimalTradeParty);
    end;
    
    TBasicDataCollector = class(TMinimalDataCollector, IBasicDataCollector)
    private
    public
      procedure FillTradePartyBasic(TradeParty : TBasicTradeParty);
    end;
    
    procedure TMinimalDataCollector.FillTradeParty(TradeParty: TMinimalTradeParty);
    begin
      TradeParty.TradeAddress.CountryId := 'FR';
    end;
    
    procedure TBasicDataCollector.FillTradePartyBasic(TradeParty: TBasicTradeParty);
    begin
      FillTradeParty(TradeParty); // <= Le problème se trouve ici
    
      TradeParty.TradeAddress.PostCode := '75018';
      TradeParty.TradeAddress.LineOne := '35 rue d''ici';
      TradeParty.TradeAddress.LineTwo := 'Line 2';
      TradeParty.TradeAddress.LineThree := 'Line 3';
      TradeParty.TradeAddress.CityName := 'PARIS';
    end;
    Lorsque j'arrive dans FillTradePartyBasic :
    - TradeParty pointe sur une adresse mémoire A
    - TradePartie.TradeAddress pointe sur une adresse mémoire B

    Lorsque j'arrive dans FillTradeParty :
    - TradeParty pointe toujours sur l'adresse mémoire A
    - Mais TradePartie.TradeAddress pointe sur une adresse mémoire C (c'est le comportement que je ne comprends pas).

    Et du coup CountryId n'est pas renseigné en sortant de FillTradeParty
    Qu'est ce que j'ai fait de travers ?
    Merci.

  2. #2
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    novembre 2002
    Messages
    7 536
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : novembre 2002
    Messages : 7 536
    Points : 24 883
    Points
    24 883
    Par défaut
    c'est normal, tu as bien deux instances distinctes TMinimalTradeParty.FTradeAddress et TBasicTradeParty.FTradeAddress

    il y a plusieurs solutions, mais en tout état de cause, tu ne dois pas déclarer deux fois FTradeAdress, et surtout ne pas l'instancier deux fois

    tu pourrais avoir quelque chose 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
     
    constructor TMinimalTradeParty.Create;
    begin
      CreateTradeAddress();
    end;
     
    procedure TMinimalTradeParty.CreateTradeAddress; // virtual
    begin
      FTradeAddress   := TMinimalTradeAddress.Create;
    end;
     
    procedure TBasicTradeParty.CreateTradeAddress; // override
    begin
      FTradeAddress   := TBasicTradeAddress.Create;
    end;
    ou si tu veux éviter d'écrire TBasicTradeAddress(FTradAddress) à chaque fois :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    procedure TBasicTradeParty.CreateTradeAddress; // override
    begin
      FBasicTradeAddress   := TBasicTradeAddress.Create;
      FTradeAddress := FBasicTradeAddress;
    end;
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  3. #3
    Membre émérite
    Avatar de ALWEBER
    Homme Profil pro
    Expert Delphi
    Inscrit en
    mars 2006
    Messages
    1 202
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Expert Delphi

    Informations forums :
    Inscription : mars 2006
    Messages : 1 202
    Points : 2 260
    Points
    2 260
    Billets dans le blog
    6
    Par défaut
    Essaye de mettre ton exemple dans un zip compilable car a priori il y a des anomalies dans ce que tu nous a envoyé.
    Cordialement

  4. #4
    Expert confirmé
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    mai 2002
    Messages
    2 971
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : mai 2002
    Messages : 2 971
    Points : 4 914
    Points
    4 914
    Par défaut
    salut

    il y a quelque lacune sur la POO

    voici qulque notion a bien avoir en tete

    encapsulation :
    Private => l'accès aux données est réservé aux méthode(Procedure fonction) de sa propre classe.
    Protected => l'accès aux données est réservé aux méthode(Procedure fonction) de sa propre classe et des classes héritières
    Public => tout le monde peut y accéder

    Heritage :

    L'héritage facilite la réutilisation du code.
    les objets d'une classe ont accès aux données et aux méthodes de la classe parent et peuvent les étendre

    Attention : si tu redefini les méthodes ou les variable il s'agit alors de surcharge tu perd la notion d'heritage
    polymorphisme :
    Le polymorphisme permet de manipuler des objets sans en connaître tout à fait le type tout en se basant sur la relation d’héritage.
    Nous souhaitons la vérité et nous trouvons qu'incertitude. [...]
    Nous sommes incapables de ne pas souhaiter la vérité et le bonheur, et sommes incapables ni de certitude ni de bonheur.
    Blaise Pascal
    PS : n'oubliez pas le tag

  5. #5
    Membre émérite
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    mars 2005
    Messages
    1 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : mars 2005
    Messages : 1 459
    Points : 2 626
    Points
    2 626
    Par défaut
    Citation Envoyé par Paul TOTH Voir le message
    c'est normal, tu as bien deux instances distinctes TMinimalTradeParty.FTradeAddress et TBasicTradeParty.FTradeAddress

    il y a plusieurs solutions, mais en tout état de cause, tu ne dois pas déclarer deux fois FTradeAdress, et surtout ne pas l'instancier deux fois

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    procedure TBasicTradeParty.CreateTradeAddress; // override
    begin
      FBasicTradeAddress   := TBasicTradeAddress.Create;
      FTradeAddress := FBasicTradeAddress;
    end;
    Y'a des fois où je mérite des baffes.
    ça aurait dû me sauter au yeux...

    Pour ceux qui aurait le même problème, je complète la réponse de Paul TOTH.
    Il faut non seulement virtualiser et surcharger une méthode CreateTradeAddress mais également une méthode GetTradeAddress à placer en lecture des propriétés TradeAddress.
    Cela implique de placer un reintroduce à la place du override pour changer le type dans la version Basique.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    function TMinimalTradeParty.GetTradeAddress: TMinimalTradeAddress;
    begin
      Result := FMinimalTradeAddress;
    end;
     
    function TBasicTradeParty.GetTradeAddress: TBasicTradeAddress;
    begin
      Result := (FMinimalTradeAddress as TBasicTradeAddress);
    end;
    Citation Envoyé par ALWEBER
    Essaye de mettre ton exemple dans un zip compilable car a priori il y a des anomalies dans ce que tu nous a envoyé.
    Cordialement
    J'ai volontairement raccourci les noms des classes.
    A l'origine, ils sont beaucoup plus long mais du coup, j'ai réécrit vite fait, il est possible que j'ai fait quelques erreurs de copier-coller.


    Citation Envoyé par anapurna
    salut

    il y a quelque lacune sur la POO

    Heritage :

    L'héritage facilite la réutilisation du code.
    les objets d'une classe ont accès aux données et aux méthodes de la classe parent et peuvent les étendre

    Attention : si tu redefini les méthodes ou les variable il s'agit alors de surcharge tu perd la notion d'heritage.
    A mon avis, il y a surtout un gros manque de sommeil.
    Mais il est toujours pas de rappeler les bases. Merci.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Perf/Bug??]9.2.0.1-Problème de performance bizarre.
    Par Le nain Attila dans le forum Oracle
    Réponses: 25
    Dernier message: 07/12/2005, 15h37
  2. Problème d'héritage ?
    Par Romanops dans le forum WinDev
    Réponses: 2
    Dernier message: 16/11/2005, 18h18
  3. Problème socket raw ? bizarre :~
    Par MonsieurAk dans le forum Windows
    Réponses: 2
    Dernier message: 12/07/2005, 15h12
  4. Problème d'héritage d'une méthode protégée
    Par shenron666 dans le forum C++
    Réponses: 9
    Dernier message: 29/04/2005, 00h17
  5. Problème de LINK Bizarre !!
    Par Jasmine dans le forum MFC
    Réponses: 24
    Dernier message: 19/03/2004, 16h58

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