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 :

[C++\Delphi] Interface, Héritage et Supports !


Sujet :

Langage Delphi

  1. #1
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 460
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 460
    Points : 24 874
    Points
    24 874
    Par défaut [C++\Delphi] Interface, Héritage et Supports !
    Depuis quelques mois, je suis passé sur C++Builder
    J'ai eu quelques déboires avec
    Mêmes méthodes dans deux interfaces héritées (une erreur de ma part, un oubli)
    Interface dont l'implémentation est réparti dans plusieurs classes (un bug corrigé en BDS2010 comme j'utilise du TObject, j'ai du relayé mes méthodes d'interface par des méthodes abstraites, cela m'évite de recopier un objet de 1000 lignes de code dans chaque implémentation)

    Je suis en train de concevoir des DLL pour encapsuler des Caméra IP, Enregistreurs Vidéos et plus tard des Centrales d'Intrusion !
    Pour cela j'ai construit tout un mécanisme pour gérer du "Hardware" générique.
    Un Hardware expose un "Purpose", chaque type de matériel aura un Purpose différent qui sera implémenté dans les différentes DLL en fonction de la marque comme Axis, Dahua, Panasonic... et du modèle\série

    Hardware, c'est codé en interface C++ virtual pure sur du TObject (ce dernier apporte quand même un confort dans le code par rapport au objet c++ même si je dois jongler un peu pour mes interfaces)
    Purpose codé en Delphi Interface et TInterfacedObject

    J'ai choisi le "Delphi Interface" pour le Purpose pour la gestion du Supports (en C++ Builder, as n'existe pas !)
    Encore "Delphi Interface" est une bidouille, une enveloppe par dessu un interface C++ virtual pure, mais cela fourni le compteur de référence grâce aux instances à allocation statique

    Mon Delphi XE d'ailleurs fume sur le Supports, si je lui passe une instance de l'objet ObjFirstEx, il me fait des VA ensuite (Ref = 0 !!!), d'où l'utilisation du MetaClass !

    Mais ce Supports ne fonctionne pas comme prévu !
    En Delphi, Support et as, fonctionne de la même façon, je peux donc comparer C++2007, C++XE, DelphiXE

    Même problème rencontré dans Interface et héritage
    et m'inspirant du sujet Les limites de l'implements ?, j'ai testé la re-déclaration (voir FrmInterfaceAbstraction)

    Tout ce joue sur le commentaire de {, IFirstDelphiInterface}Il ne devrait pas être nécessaire puisque IFirstExtendedDelphiInterface hérite déjà de IFirstDelphiInterface, en objet pur C++ (côté DLL cela fonctionne), mais pour le Supports (côté EXE), cela ne passe pas, car il ne prend pas en compte le GUID de IFirstDelphiInterface mais seulement celui de IFirstExtendedDelphiInterface !

    L'anomalie se produit dans un code sans DLL comme dans l'exemple plus bas !
    Est-ce une anomalie ?
    Est-ce un délire d'hériter Interface d'une autre une Interface ? (en gros IInterface serait l'exception à la règle)

    Du coup, il faut mettre les deux !
    C'est vilain (et risque d'oubli !!!)

    Qu'en pensez vous ?

    Existe-t-il un moyen pour qu'il utilise un GUID hérité sans devoir explicitement le répéter !
    Surtout que C++Builder 2007, j'ai un warning "La classe de base 'classe1' est aussi une classe de base de 'classe2' (W8024)"
    que je désactive comme ceci

    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #pragma option push -w-ibc
    class TImpll : public TInterfacedObject, private/*supports*/ IGenericPurpose, public ICameraPurpose
    {
    ...
    };
    #pragma option pop



    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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    unit FrmInterfaceAbstraction;
     
    interface
     
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, Vcl.StdCtrls;
     
    type
      TInterfaceAbstractionForm = class(TForm)
        BtnDelphiIntfAndImplHierarchy: TButton;
        MemoTrace: TMemo;
        procedure BtnDelphiIntfAndImplHierarchyClick(Sender: TObject);
      private
        { Déclarations privées }
      public
        { Déclarations publiques }
      end;
     
      IFirstDelphiInterface = interface
        ['{F95FFF42-F65A-4C3E-99D0-468658ED5641}']
     
        function A(): Integer; //stdcall;
        function B(): Integer; //stdcall;
      end;
     
      IFirstExtendedDelphiInterface = interface(IFirstDelphiInterface)
        ['{A96CD381-0F06-4D56-AB6D-E2F6C4F22262}']
     
        function E(): Integer; //stdcall;
        function F(): Integer; //stdcall;
      end;
     
      //---------------------------------------------------------------------------
      TFirstExImplDelphiIntf = class(TInterfacedObject{, IFirstDelphiInterface}, IFirstExtendedDelphiInterface)
      public
        function A(): Integer; //stdcall;
        function B(): Integer; //stdcall;
        function E(): Integer; //stdcall;
        function F(): Integer; //stdcall;
      end;
     
    var
      InterfaceAbstractionForm: TInterfaceAbstractionForm;
     
    implementation
     
    {$R *.dfm}
     
    //---------------------------------------------------------------------------
    function TFirstExImplDelphiIntf.A(): Integer; //stdcall;
    begin
      Result := 111;
    end;
     
    function TFirstExImplDelphiIntf.B(): Integer; //stdcall;
    begin
      Result := 222;
    end;
     
    function TFirstExImplDelphiIntf.E(): Integer; //stdcall;
    begin
      Result := 555;
    end;
     
    function TFirstExImplDelphiIntf.F(): Integer; //stdcall;
    begin
      Result := 666;
    end;
    //---------------------------------------------------------------------------
     
     
     
    //---------------------------------------------------------------------------
    procedure TInterfaceAbstractionForm.BtnDelphiIntfAndImplHierarchyClick(Sender: TObject);
    var
      ObjFirstEx: TFirstExImplDelphiIntf;
      intfFirst: IFirstDelphiInterface;
      intfFirstEx: IFirstExtendedDelphiInterface;
      I: Integer;
    begin
     
     
      ObjFirstEx := TFirstExImplDelphiIntf.Create();
      try
        MemoTrace.Lines.Add('Supports(ObjFirstEx, IInterface) : ' + BoolToStr(Supports(TFirstExImplDelphiIntf, IInterface), true));
        MemoTrace.Lines.Add('Supports(ObjFirstEx, IFirstDelphiInterface) : ' + BoolToStr(Supports(TFirstExImplDelphiIntf, IFirstDelphiInterface), true));
        MemoTrace.Lines.Add('Supports(ObjFirstEx, IFirstExtendedDelphiInterface) : ' + BoolToStr(Supports(TFirstExImplDelphiIntf, IFirstExtendedDelphiInterface), true));
      except
        on E: Exception do
          MemoTrace.Lines.Add(E.Message);
      end;
     
      try
        MemoTrace.Lines.Add('First Ex');
        MemoTrace.Lines.Add('as First');
        intfFirst := ObjFirstEx as IFirstDelphiInterface;
        MemoTrace.Lines.Add('as FirstExtended');
        intfFirstEx := ObjFirstEx as IFirstExtendedDelphiInterface;
     
        if Assigned(intfFirst) then
        begin
          MemoTrace.Lines.Add(Format('A : %d == %d ?', [ObjFirstEx.A(), intfFirst.A()]));
          MemoTrace.Lines.Add(Format('B : %d == %d ?', [ObjFirstEx.B(), intfFirst.B()]));
        end;
     
        if Assigned(intfFirstEx) then
        begin
          MemoTrace.Lines.Add(Format('E : %d == %d ?', [ObjFirstEx.E(), intfFirstEx.E()]));
          MemoTrace.Lines.Add(Format('F : %d == %d ?', [ObjFirstEx.F(), intfFirstEx.F()]));
        end;
      except
        on E: Exception do
          MemoTrace.Lines.Add(E.Message);
      end;
      MemoTrace.Lines.Add('');
     
    end;
     
    end.
    Et la version d'origine en C++, selon 2007 ou XE, il y a des trucs qui ont été corrigés entre temps !

    Code c++ : 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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    //---------------------------------------------------------------------------
     
    #include <vcl.h>
    #pragma hdrstop
     
    #include "Frm_InterfaceAbstraction.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    //---------------------------------------------------------------------------
    __fastcall TInterfaceAbstractionForm::TInterfaceAbstractionForm(TComponent* Owner)
      : TForm(Owner)
    {
    }
     
    //---------------------------------------------------------------------------
    __interface INTERFACE_UUID ("{F95FFF42-F65A-4C3E-99D0-468658ED5641}") IFirstDelphiInterface : public IInterface
    {
    public:
      virtual int __stdcall A() = 0;
      virtual int __stdcall B() = 0;
    };
    typedef System::DelphiInterface<IFirstDelphiInterface> _di_FirstDelphiInterface; // DelphiInterface
     
    __interface INTERFACE_UUID ("{150AA670-7C9D-4CE7-BE7A-C5AC4CB31DEF}") ISecondDelphiInterface : public IInterface
    {
    public:
      virtual int __stdcall C() = 0;
      virtual int __stdcall D() = 0;
    };
    typedef System::DelphiInterface<ISecondDelphiInterface> _di_SecondDelphiInterface; // DelphiInterface
     
    __interface INTERFACE_UUID ("{A96CD381-0F06-4D56-AB6D-E2F6C4F22262}") IFirstExtendedDelphiInterface : public IFirstDelphiInterface
    {
    public:
      virtual int __stdcall E() = 0;
      virtual int __stdcall F() = 0;
    };
    typedef System::DelphiInterface<IFirstExtendedDelphiInterface> _di_FirstExtendedDelphiInterface; // DelphiInterface
    //---------------------------------------------------------------------------
     
     
    //---------------------------------------------------------------------------
    class TStepByStepImplDelphiIntfAB: public TInterfacedObject, public IFirstDelphiInterface
    {
    public:
      int __stdcall A() {return -1;}
      int __stdcall B() {return -2;}
     
      virtual HRESULT __stdcall QueryInterface(const GUID& IID, void **Obj){return TInterfacedObject::QueryInterface(IID, Obj);}
      virtual ULONG __stdcall AddRef() {return TInterfacedObject::_AddRef();}
      virtual ULONG __stdcall Release() {return TInterfacedObject::_Release();}
    };
     
    class TStepByStepImplDelphiIntfABCD: public TStepByStepImplDelphiIntfAB, public ISecondDelphiInterface
    {
    public:
      int __stdcall C() {return -3;}
      int __stdcall D() {return -4;}
     
      virtual HRESULT __stdcall QueryInterface(const GUID& IID, void **Obj){return TInterfacedObject::QueryInterface(IID, Obj);}
      virtual ULONG __stdcall AddRef() {return TInterfacedObject::_AddRef();}
      virtual ULONG __stdcall Release() {return TInterfacedObject::_Release();}
    };
     
    //---------------------------------------------------------------------------
    class TSeparateImplDelphiIntfA: public TInterfacedObject, public IFirstDelphiInterface
    {
    public:
      int __stdcall A() {return -1;}
     
      virtual HRESULT __stdcall QueryInterface(const GUID& IID, void **Obj){return TInterfacedObject::QueryInterface(IID, Obj);}
      virtual ULONG __stdcall AddRef() {return TInterfacedObject::_AddRef();}
      virtual ULONG __stdcall Release() {return TInterfacedObject::_Release();}
    };
     
    class TSeparateImplDelphiIntfAB: public TSeparateImplDelphiIntfA
    {
    public:
      int __stdcall B() {return -2;}
    };
     
    class TSeparateImplDelphiIntfABCD: public TSeparateImplDelphiIntfAB, public ISecondDelphiInterface
    {
    public:
      int __stdcall C() {return -3;}
      int __stdcall D() {return -4;}
     
      virtual HRESULT __stdcall QueryInterface(const GUID& IID, void **Obj){return TInterfacedObject::QueryInterface(IID, Obj);}
      virtual ULONG __stdcall AddRef() {return TInterfacedObject::_AddRef();}
      virtual ULONG __stdcall Release() {return TInterfacedObject::_Release();}
    };
     
    //---------------------------------------------------------------------------
    class TFirstAndSecondImplDelphiIntf: public TInterfacedObject, public IFirstDelphiInterface, public ISecondDelphiInterface
    {
    public:
      int __stdcall A() {return -1;}
      int __stdcall B() {return -22;}
      int __stdcall C() {return -333;}
      int __stdcall D() {return -4444;}
     
      virtual HRESULT __stdcall QueryInterface(const GUID& IID, void **Obj){return TInterfacedObject::QueryInterface(IID, Obj);}
      virtual ULONG __stdcall AddRef() {return TInterfacedObject::_AddRef();}
      virtual ULONG __stdcall Release() {return TInterfacedObject::_Release();}
    };
     
    //---------------------------------------------------------------------------
    class TFirstExImplDelphiIntf: public TInterfacedObject, public IFirstExtendedDelphiInterface
    {
    public:
      int __stdcall A() {return -1;}
      int __stdcall B() {return -22;}
      int __stdcall E() {return -55555;}
      int __stdcall F() {return -666666;}
     
      virtual HRESULT __stdcall QueryInterface(const GUID& IID, void **Obj){return TInterfacedObject::QueryInterface(IID, Obj);}
      virtual ULONG __stdcall AddRef() {return TInterfacedObject::_AddRef();}
      virtual ULONG __stdcall Release() {return TInterfacedObject::_Release();}
    };
     
    //---------------------------------------------------------------------------
    class TFirstAndFirstExImplDelphiIntf: public TInterfacedObject, public IFirstDelphiInterface, public IFirstExtendedDelphiInterface
    {
    public:
      int __stdcall A() {return -1;}
      int __stdcall B() {return -22;}
      int __stdcall E() {return -55555;}
      int __stdcall F() {return -666666;}
     
      virtual HRESULT __stdcall QueryInterface(const GUID& IID, void **Obj){return TInterfacedObject::QueryInterface(IID, Obj);}
      virtual ULONG __stdcall AddRef() {return TInterfacedObject::_AddRef();}
      virtual ULONG __stdcall Release() {return TInterfacedObject::_Release();}
    };
     
    //---------------------------------------------------------------------------
    void __fastcall TInterfaceAbstractionForm::BtnDelphiIntfAndImplHierarchyClick(
          TObject *Sender)
    {
      _di_FirstDelphiInterface intfFirst;
      _di_SecondDelphiInterface intfSecond;
      _di_FirstExtendedDelphiInterface intfFirstEx;
     
      bool FlagFirst;
      bool FlagSecond;
      bool FlagFirstEx;
     
      TFirstAndSecondImplDelphiIntf* ObjTogether = new TFirstAndSecondImplDelphiIntf();
     
      FlagFirst = ObjTogether->IFirstDelphiInterface::Supports(intfFirst);
      FlagSecond = ObjTogether->ISecondDelphiInterface::Supports(intfSecond); // La Seule fois où ça passe !
      MemoTrace->Lines->Add("Together");
      if (FlagFirst)
      {
        MemoTrace->Lines->Add(Format("A : %d == %d ?", ARRAYOFCONST((ObjTogether->A(), intfFirst->A()))));
        MemoTrace->Lines->Add(Format("B : %d == %d ?", ARRAYOFCONST((ObjTogether->B(), intfFirst->B()))));
      }
      if (FlagSecond)
      {
        MemoTrace->Lines->Add(Format("C : %d == %d ?", ARRAYOFCONST((ObjTogether->C(), intfSecond->C()))));
        MemoTrace->Lines->Add(Format("D : %d == %d ?", ARRAYOFCONST((ObjTogether->D(), intfSecond->D()))));
      }
      MemoTrace->Lines->Add("");
     
      // ----
     
      TFirstExImplDelphiIntf* ObjFirstEx = new TFirstExImplDelphiIntf();
     
      FlagFirst = ObjFirstEx->Supports(intfFirst);
      FlagFirstEx = ObjFirstEx->Supports(intfFirstEx);
      MemoTrace->Lines->Add("First Ex");
      if (FlagFirst)
      {
        MemoTrace->Lines->Add(Format("A : %d == %d ?", ARRAYOFCONST((ObjFirstEx->A(), intfFirst->A()))));
        MemoTrace->Lines->Add(Format("B : %d == %d ?", ARRAYOFCONST((ObjFirstEx->B(), intfFirst->B()))));
      }
      if (FlagFirstEx)
      {
        MemoTrace->Lines->Add(Format("E : %d == %d ?", ARRAYOFCONST((ObjFirstEx->E(), intfFirstEx->E()))));
        MemoTrace->Lines->Add(Format("F : %d == %d ?", ARRAYOFCONST((ObjFirstEx->F(), intfFirstEx->F()))));
      }
      MemoTrace->Lines->Add("");
     
      // ----
     
      TFirstAndFirstExImplDelphiIntf* ObjFirstAndFirstEx = new TFirstAndFirstExImplDelphiIntf();
     
      FlagFirst = ObjFirstAndFirstEx->IFirstExtendedDelphiInterface::Supports(intfFirst); // Cela fonctionne contre toute attente en 2007 et XE
      FlagFirstEx = ObjFirstAndFirstEx->IFirstExtendedDelphiInterface::Supports(intfFirstEx);
      MemoTrace->Lines->Add("First And First Ex");
      if (FlagFirst)
      {
        MemoTrace->Lines->Add(Format("A : %d == %d ?", ARRAYOFCONST((ObjFirstAndFirstEx->A(), intfFirst->A()))));
        MemoTrace->Lines->Add(Format("B : %d == %d ?", ARRAYOFCONST((ObjFirstAndFirstEx->B(), intfFirst->B()))));
      }
      if (FlagFirstEx)
      {
        MemoTrace->Lines->Add(Format("E : %d == %d ?", ARRAYOFCONST((ObjFirstAndFirstEx->E(), intfFirstEx->E()))));
        MemoTrace->Lines->Add(Format("F : %d == %d ?", ARRAYOFCONST((ObjFirstAndFirstEx->F(), intfFirstEx->F()))));
      }
      MemoTrace->Lines->Add("");
     
      // ----
     
      TSeparateImplDelphiIntfABCD* ObjSeparate = new TSeparateImplDelphiIntfABCD();
     
      FlagFirst = ObjSeparate->IFirstDelphiInterface::Supports(intfFirst);
      #if (__BCPLUSPLUS__ > 0x593)
      FlagSecond = ObjSeparate->ISecondDelphiInterface::Supports(intfSecond); // Belle VA sous 2007
      #else
      FlagSecond = ObjSeparate->IFirstDelphiInterface::Supports(intfSecond); // Compile, execution sans VA mais renvoie false ! Evidemment !
      #endif
     
      MemoTrace->Lines->Add("Separate");
      if (FlagFirst)
      {
        MemoTrace->Lines->Add(Format("A : %d == %d ?", ARRAYOFCONST((ObjSeparate->A(), intfFirst->A()))));
     
        // Mon BCB2007 est en version 593, une version 2009 ou plus, devrait avoir un plus grand chiffre !
        #if (__BCPLUSPLUS__ > 0x593)
        MemoTrace->Lines->Add(Format("B : %d == %d ?", ARRAYOFCONST((ObjSeparate->B(), intfFirst->B()))));
        #else
        MemoTrace->Lines->Add("B Ignoré en 2007");
        #endif
      }
      if (FlagSecond)
      {
        MemoTrace->Lines->Add(Format("C : %d == %d ?", ARRAYOFCONST((ObjSeparate->C(), intfSecond->C()))));
        MemoTrace->Lines->Add(Format("D : %d == %d ?", ARRAYOFCONST((ObjSeparate->D(), intfSecond->D()))));
      }
      MemoTrace->Lines->Add("");
     
      // ----
     
      TStepByStepImplDelphiIntfABCD* ObjStepByStep = new TStepByStepImplDelphiIntfABCD();
     
      FlagFirst = ObjStepByStep->IFirstDelphiInterface::Supports(intfFirst);
      #if (__BCPLUSPLUS__ > 0x593)
      FlagSecond = ObjStepByStep->ISecondDelphiInterface::Supports(intfSecond); // Belle VA sous 2007
      #else
      FlagSecond = ObjStepByStep->IFirstDelphiInterface::Supports(intfSecond); // Compile, execution sans VA mais renvoie false ! Evidemment !
      #endif
     
      MemoTrace->Lines->Add("StepByStep");
      if (FlagFirst)
      {
        MemoTrace->Lines->Add(Format("A : %d == %d ?", ARRAYOFCONST((ObjStepByStep->A(), intfFirst->A()))));
        MemoTrace->Lines->Add(Format("B : %d == %d ?", ARRAYOFCONST((ObjStepByStep->B(), intfFirst->B()))));
      }
      if (FlagSecond)
      {
        MemoTrace->Lines->Add(Format("C : %d == %d ?", ARRAYOFCONST((ObjStepByStep->C(), intfSecond->C()))));
        MemoTrace->Lines->Add(Format("D : %d == %d ?", ARRAYOFCONST((ObjStepByStep->D(), intfSecond->D()))));
      }
      MemoTrace->Lines->Add("");
     
      // ----
     
    }
    //---------------------------------------------------------------------------
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  2. #2
    Expert éminent sénior

    Avatar de sjrd
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2004
    Messages
    4 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2004
    Messages : 4 517
    Points : 10 154
    Points
    10 154
    Par défaut
    J'ai pas tout compris, mais :
    Citation Envoyé par ShaiLeTroll Voir le message
    Tout ce joue sur le commentaire de {, IFirstDelphiInterface}Il ne devrait pas être nécessaire puisque IFirstExtendedDelphiInterface hérite déjà de IFirstDelphiInterface, en objet pur C++ (côté DLL cela fonctionne), mais pour le Supports (côté EXE), cela ne passe pas, car il ne prend pas en compte le GUID de IFirstDelphiInterface mais seulement celui de IFirstExtendedDelphiInterface !

    L'anomalie se produit dans un code sans DLL comme dans l'exemple plus bas !
    Est-ce une anomalie ?
    Est-ce un délire d'hériter Interface d'une autre une Interface ? (en gros IInterface serait l'exception à la règle)

    Du coup, il faut mettre les deux !
    C'est vilain (et risque d'oubli !!!)
    Pourtant c'est bien as designed.

    Il est tout à fait prévu, en Delphi, que si un objet implémente une interface IChildIntf héritant IParentIntf, ce n'est pas pour autant que cet objet implémente IParentIntf.

    Par contre, l'implémentation d'une interface particulière est héritée d'une classe parent à une classe enfant. C'est ce qui fait que toutes les classes enfant de TInterfacedObject implémentent IInterface.

    L'héritage d'interface n'est pas abérent, mais n'est pas une relation de is-a. C'est une relation de "définit les mêmes méthodes + les suivantes".
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
    Découvrez Mes tutoriels.

  3. #3
    Membre expérimenté Avatar de guillemouze
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    876
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2004
    Messages : 876
    Points : 1 448
    Points
    1 448
    Par défaut
    Citation Envoyé par sjrd Voir le message
    Il est tout à fait prévu, en Delphi, que si un objet implémente une interface IChildIntf héritant IParentIntf, ce n'est pas pour autant que cet objet implémente IParentIntf.
    En es-tu sur ?
    Si oui, peux tu m'expliquer pourquoi, quand tu declare une interface qui herite implicitement de IInterface, et que tu declare un objet (TObject) qui implemente cette interface, il faut en plus implementer les methode de IInterface ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    type
      IMonItf = interface
        procedure itfProc;
      end;
     
      TMonObj= class(TObject, IMonItf)
      public
        procedure itfProc;
        //ne compile pas, il manque _AddRef, ... (les methodes de IInterface)
      end;
    Je n'ai pas essayé avec une autre "IParentIntf" que IInterface, mais je suppose que c'est la meme chose, ce qui va a l'encontre de ce que tu dis

  4. #4
    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
    Citation Envoyé par guillemouze Voir le message
    En es-tu sur ?
    Si oui, peux tu m'expliquer pourquoi, quand tu declare une interface qui herite implicitement de IInterface, et que tu declare un objet (TObject) qui implemente cette interface, il faut en plus implementer les methode de IInterface ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    type
      IMonItf = interface
        procedure itfProc;
      end;
     
      TMonObj= class(TObject, IMonItf)
      public
        procedure itfProc;
        //ne compile pas, il manque _AddRef, ... (les methodes de IInterface)
      end;
    Je n'ai pas essayé avec une autre "IParentIntf" que IInterface, mais je suppose que c'est la meme chose, ce qui va a l'encontre de ce que tu dis
    ce n'est pas contradictoire avec ce qu'il a dit

    IMonItf hérite des méthodes de IInterface, un objet qui implémente IMonItf doit donc implémenter _AddRef ... MAIS ce n'est pas pour cela que TMonObj supporte IInterface

    démonstration (sous D6)

    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
     
    type
      IDemo = interface
        procedure demo;
      end;
     
      TDemo = class(TObject, IDemo)
      // IInterface
        function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
        function _AddRef: Integer; stdcall;
        function _Release: Integer; stdcall;
      // IDemo
        procedure demo;
      end;
     
    procedure TForm1.FormCreate(Sender: TObject);
    var
      demo : TDemo;
      test1: IDemo;
      test2: IInterface;
    begin
      demo := TDemo.Create;
      test1 := demo;
      test2 := demo;
    end;
    nul besoin d'implémenter TDemo, la compilation me refuse test2 "Types incompatibles IInterface et TDemo" alors que test1 ne pose pas de problème.

    et tu aurais le même résultat en runtime avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
      if demo.QueryInterface(IInterface, test2) <> 0 then
        raise Exception.Create('IInterface non défini');
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 460
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 460
    Points : 24 874
    Points
    24 874
    Par défaut
    Ah merci à tous trois !

    Citation Envoyé par sjrd Voir le message
    Pourtant c'est bien as designed.
    Tu peux expliquer ce terme ?
    Est-ce que tu indique une différence du comportement du as
    - Obj as Class : (héritage implicite)
    - Obj as Intf : (héritage explicite)

    J'ai toujours codé en Delphi en faisant des Abstract au lieu de faire des Interface !
    Sans m'en rendre compte, la structure même du langage C++, on ne fait que des Abstract, le type Interface n'apparait qu'avec le DelphiInterface ou TComInterface (couche Borland pour les ATL de Microsoft)


    Citation Envoyé par sjrd Voir le message
    Il est tout à fait prévu, en Delphi, que si un objet implémente une interface IChildIntf héritant IParentIntf, ce n'est pas pour autant que cet objet implémente IParentIntf.
    C'est très subtile !

    0- Supports(TFirstExImplDelphiIntf, IInterface).
    1- Supports(TFirstExImplDelphiIntf, IFirstDelphiInterface).
    2- Supports(TFirstExImplDelphiIntf, IFirstExtendedDelphiInterface).

    Si TImpl= class(TObject, IFirstExtendedDelphiInterface)alors, on a False, False, True car même si IFirstExtendedDelphiInterface hérite des deux autres interfaces, il n'implémente que cette dernière dans sa globalité et non les trois une par une !

    Si TImpl= class(TInterfacedObject, IFirstExtendedDelphiInterface)Comme TInterfacedObject implémente explicitement IInterface, on obtient True, False, True, TInterfacedObject fourni IInterface et TImpl fourni IFirstExtendedDelphiInterface
    on obtient un résultat similaire

    Si TImpl= class(TObject, IInterface, IFirstExtendedDelphiInterface)il y a juste plus de travail, est-ce que "implements" en Delphi permet d'utiliser un TInterfacedObject en délégation, parfois l'héritage de TInterfacedObject peut-être contraire à une architecture déjà défini (bon, c'est un autre sujet, je suis sur qu'en relisant Les limites de l'implements, j'aurais une réponse !

    Si l'on veut True, True, True, il faut explicitement déclaré comme ceci :
    TImpl= class(TObject, IInterface, IFirstDelphiInterface, IFirstExtendedDelphiInterface),
    ou :
    TImpl= class(TInterfaceObject, IFirstDelphiInterface, IFirstExtendedDelphiInterface)
    En C++ Builder, ce comportement n'est pas aussi visible qu'en Delphi !
    Pour le moment, j'ai fait des pseudo-interface C++ qui ne sont que des classes abstraites pures !
    D'ailleurs, on implémente ces pseudo-interface !
    Si l'on utilise que ces types, pas besoin de "as" (qui n'existe pas ), pas héritage les pointeurs de classes sont compatibles (je rappel qu'en C++, le TObject est forcément déclaré en TObject*, on a une référence explicite)
    Mais si l'on utilise les DelphiInterface (une template <Interface>) qui sont des objets à allocation statique avec l'opérateur = d'affectation surchargé pour que l'on puisse affecter un Interface* à un objet DI<Interface>
    C'est à partir de ce moment où les objets nécessite Supports ! car évidemment DI<ITruc> n'est pas affectable dans un DI<IBidule> même si ITruc hérite de IBidule, alors qu'en pseudo-interface C++ on peut écire IBidule *Bidule = Truc avec ITruc* Truc

    Bon je vais revoir ma copie, je ne veux pas être forcé de mettre IFirstDelphiInterface à chaque fois, c'est la dernière étape d'implémentation et c'est un risque de l'oublier !

    Je vais donc me faire un objet héritant de TInterfacedObject qui implémente IFirstDelphiInterface
    Cela m'oblige à faire des méthodes abstraites pour le relais de quelques fonctions à cause du Bug de VMT de C++2007, mais bon, au moins cela me protège contre l'oubli !

    Au final, j'aurais

    TAbstractImpl= class(TInterfacedObject, IFirstDelphiInterface).

    TImpl= class(TAbstractImpl, IFirstExtendedDelphiInterface).
    TImplBis= class(TAbstractImpl, IFirstBisDelphiInterface).
    TImplTer= class(TAbstractImpl, IFirstTerDelphiInterface).
    ... les implémentations seront TRES nombreuses pour chaque type de matériel, pour chaque marque et pour chaque modèle ... mais là tout dépend du commercial et ce qu'il vend !
    C'est pour cela que je tiens à une "structure" forte du code !

    EDIT :


    Code c++ : 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
    //---------------------------------------------------------------------------
    class TFirstAbstractImplDelphiIntf: public TInterfacedObject, public IFirstDelphiInterface
    {
     
    };
     
    //---------------------------------------------------------------------------
    class TFirstExRelayedImplDelphiIntf: public TFirstAbstractImplDelphiIntf, public IFirstExtendedDelphiInterface
    {
    public:
      int __stdcall A() {return -11;}
      int __stdcall B() {return -222;}
      int __stdcall E() {return -555555;}
      int __stdcall F() {return -6666666;}
     
      virtual HRESULT __stdcall QueryInterface(const GUID& IID, void **Obj){return TInterfacedObject::QueryInterface(IID, Obj);}
      virtual ULONG __stdcall AddRef() {return TInterfacedObject::_AddRef();}
      virtual ULONG __stdcall Release() {return TInterfacedObject::_Release();}
    };

    Pour le moment,
    En 2007, je n'ai que des violations d'accès sur le Support (logique, je retombe dans mes bugs de relais, mais là, comme j'ai de l'héritage de IInterface, rien ne va plus !)

    En XE, forcément pour me narguer cela fonctionne !

    Je crois que je vais virer l'héritage et le faire autrement !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  6. #6
    Membre expérimenté Avatar de guillemouze
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    876
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2004
    Messages : 876
    Points : 1 448
    Points
    1 448
    Par défaut
    Citation Envoyé par Paul TOTH Voir le message
    IMonItf hérite des méthodes de IInterface, un objet qui implémente IMonItf doit donc implémenter _AddRef ... MAIS ce n'est pas pour cela que TMonObj supporte IInterface
    C'est très clair. Mais je ne comprends pas pour autant la logique, théoriquement, si une classe implémente une interface IChild, elle implémente forcement IParent, et pourtant, elle support IChild, mais pas IParent ... Y a-t'il une raison a cela ?

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 460
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 460
    Points : 24 874
    Points
    24 874
    Par défaut
    Ben, tu as déjà exprimé la réponse : La Pratique ! ... et la Théorie

    Personnellement, je pense comme toi, c'est en total contradiction avec le modèle Objet et l'héritage !

    En fait, il faut penser les interfaces comme des contrats !

    tu implémente IChild, tu as donc dit que tu respectes le contrat de IChild (une méthode à lui et une méthode hérité de IParent)
    Mais tu n'as pas dit que tu respecte le contrat de IParent, tu l'implémente par indirection, c'est un effet collatéral !

    C'est une façon cohérente de voir le contrat dans sa globalité et non comme la composition de plus contrat !


    Il est possible que ce soit une limitation des Interfaces du as et du GUID en Delphi !

    Il suffit de regarder le TInterfacedObject du C++Builder :
    1- Il n'implémente pas IInterface contrairement à celui en Delphi (ben oui en c++ les interfaces c'est des classes abstraites pures seul cas de mutli-héritage supporté par la VCL
    2- La méthode QueryInterface a une signature différente de IInterface
    3- AddRef et Release ont été volontairement préfixé de _ pour éviter la confusion

    Pourquoi tous ces efforts, je suis persuadé que pour C++Builder, les développeurs VCL ont contournés certaines limitations de mélange C++ et TObject !
    Dont certaines ont disparus depuis D2010

    En C++, les interfaces n'existe pas en standard, le problème n'existe pas !
    Il faudrait le tester Delphi Prism pour voir les différences
    Normalement, ça doit être le Même en C# (puisque cela utilise le type interface du .NET et non de la VCL)

    Il faudrait le tester en Java, qui est quand même LE langage Objet et voir comment il gère cela !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  8. #8
    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 ShaiLeTroll Voir le message
    Tu peux expliquer ce terme ?
    Est-ce que tu indique une différence du comportement du as
    - Obj as Class : (héritage implicite)
    - Obj as Intf : (héritage explicite)
    C'est le même mot clé as, mais ce n'est pas du tout la même chose.

    Une classe peut hériter d'une autre classe. Lorsque tu fais un as sur une classe, tu fais un cast soit un vulgaire transtypage. L'héritage de classe en Delphi est conçu de telle sorte que la classe dérivée est compatible binairement avec la classe ancêtre. Lorsque tu l'as transtype, en fait tu ne fais absolument rien !
    Tu te contente de dire au compilateur que tu penses savoir ce que tu fais et que tu veux manipuler la classe selon sont nouveau type. Mais contrairement à un vulgaire cast, le compilateur va malgré tout vérifier que ton cast est compatible avec le polymorphisme.

    Avec les interfaces, c'est radicalement différent. Même si la syntaxe est proche, un objet n'hérite pas d'une interface. Et une interface (enfin une vrai) n'est pas une classe virtuelle pure.
    Une interface comme tu l'as indiqué c'est un contrat. La classe qui implémente l'interface s'engage à implémenter les méthodes qui y sont déclarées.
    Concrêtement, une interface est une VMT. C'est à dire que c'est un tableau de pointeurs sur les méthodes qui implémentent la déclaration de l'interface. Le tableau lui même est simplement identifié à partir d'un GUID.

    Lorsque tu fais un as sur un objet pour demander une interface, tu appelles implicitement la méthode QueryInterface en lui fournissant le GUID qui identifie le tableau de pointeur que tu demandes...
    En Delphi, le compilateur te fournit une implémentation implicite de GetInterface (qui est utilisée pour implémenter QueryInterface) en fonction de la liste des interfaces que l'objet déclare implémenter.
    Mais l'implémentation générée ne tient pas compte de la hiérarchie des GUID.

    J'ai toujours codé en Delphi en faisant des Abstract au lieu de faire des Interface !
    Sans m'en rendre compte, la structure même du langage C++, on ne fait que des Abstract, le type Interface n'apparait qu'avec le DelphiInterface ou TComInterface (couche Borland pour les ATL de Microsoft)
    Oui, en fait les interfaces qu'on manipule en Delphi ne sont pas un concepte de programmation objet, mais une invention de Microsoft pour les objets COM.
    Microsoft a introduit la spécification de IUnknown, QueryInterface, AddRef et Release pour mettre en oeuvre le concepte d'interface avec les langages existants qui ne le supportaient pas.
    En C++, les interfaces n'existent pas car on s'en sort avec la notion de classe virtuelle pure et l'héritage multiple.
    Dans les autres langages, l'héritage multiple n'existe pas. Il a fallu modifier le langage pour supporter au moins l'implémentation d'interfaces multiples.

  9. #9
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 460
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 460
    Points : 24 874
    Points
    24 874
    Par défaut
    Citation Envoyé par Franck SORIANO Voir le message
    C'est le même mot clé as, mais ce n'est pas du tout la même chose.
    Oui, je sais que "as" c'est un équivalent de Supports\QueryInterface et pas une combinaison de is + cast
    Ce qui me "choquait" était le terme "as designed" est-ce une appellation standard ?
    SJRD a sorti cela comme si c'était une chose naturelle (pour un génie surement) !

    Citation Envoyé par Franck SORIANO Voir le message
    Oui, en fait les interfaces qu'on manipule en Delphi ne sont pas un concepte de programmation objet, mais une invention de Microsoft pour les objets COM.
    Microsoft a introduit la spécification de IUnknown, QueryInterface, AddRef et Release pour mettre en oeuvre le concepte d'interface avec les langages existants qui ne le supportaient pas.
    C'est ce que j'avais déjà constaté, il y a quelques années, d'où mon abandon totale de ce type interface !


    Citation Envoyé par Franck SORIANO Voir le message
    En C++, les interfaces n'existent pas car on s'en sort avec la notion de classe virtuelle pure et l'héritage multiple.
    Dans les autres langages, l'héritage multiple n'existe pas. Il a fallu modifier le langage pour supporter au moins l'implémentation d'interfaces multiples.
    Oui, je fais déjà du cast sauvage entre les mes instances et mes interfaces !
    Par exemple, pour les libérations, si je fais un delete sur une interface, cela n'appele pas le Destroy du TObject parce que l'interface n'est pas marqué en DELPHICLASS (pour lui ça hérite de la classe abstraite c++ strict et non de TObject)
    Du coup, je cast ma pseudo-interface en l'objet qu'elle est censé être (je le sais, j'ai un factory juste au dessus, normalement, c'est le bon type), ainsi le delete est bien fait sur une DELPHICLASS\TObject et utilise Destroy virtual !

    Tu imagines que le cast sauvage interface vers instance me choque en tant que Delphi habitué au as ne fonctionnant que l'autre un sens ... quoi j'ai vu qu'il était possible (depuis XE ?) de retrouver l'instance d'une interface
    En 2003, j'avais fait une bidouille, avec une méthode ItSelf de l'interface qui renvoyait l'objet sous la forme d'un Pointer, que je castais méchamment ... déjà que l'on échangeait des integer pour les panels (c'était la VCL interne de cet employeur qui était tordue)
    Plus récemment, pour éviter cela avec un ActiveX j'avais plus ou mois fait en Delphi ce que l'on appelerait des constructeurs de copies en C++ pour échanger mes interfaces et pouvoir repartir sur des instances clonées !

    L'autre grand avantage de la DelphiInterface en C++ couplé à un TPersistentObject c'est le compteur de référence, j'ai mes fonctions qui renvoie une DI, mais pas besoin de faire la fonction de libération, le compteur de référence et comme la DI utilise Release de IInterface, cela appel implicitement le TPersistentObject.Destroy !

    C'est aussi pour cela que j'aimerais continué avec !

    Comme l'héritage ne propage pas les GUID, je l'ai retiré !

    J'utilise Supports dès que j'ai besoin de transtypage, c'est un peu plus pénible qu'avec l'héritage direct mais c'est cohérent !

    Je profite de quelques astuces C++ pour m'éviter des oublis, une petite macro

    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    #define PurposeSupports(X) : public TxxxHardwareAbstractPurpose, public IxxxHardwareEntityPurpose, public X

    un objet abstrait commun pour le coder "factorisé"

    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class TxxxHardwareAbstractPurpose : public TInterfacedObject
    {
      // Quelques fonctions de base !
    };
    Mes interfaces pour chaque type de matériel

    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    __interface IxxxDVREntityPurpose : public IInterface
    {
    public:
      // DVR Interface Methods
      ...
    }
     
    __interface IxxxCameraEntityPurpose : public IInterface
    {
    {
    public:
      // Camere Interface Methods
      ...
    }

    et j'ai mes implémentations déclarées comme ceci dans mes différentes DLL !

    Code c++ : 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
    class TxxxDVRDahuaEntityPurposeDefault PurposeSupports(IxxxDVREntityPurpose)
    {
      ... implementations !
    }
     
    class TxxxDVRPanasonicEntityPurposeDefault PurposeSupports(IxxxDVREntityPurpose)
    {
      ... implementations !
    }
     
    class TxxxCameraAxisEntityPurposeDefault PurposeSupports(IxxxCameraEntityPurpose)
    {
      ... implementations !
    }
     
    class TxxxCameraGenericOnDVREntityPurposeDefault PurposeSupports(IxxxCameraEntityPurpose)
    {
      ... implementations !
    }
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  10. #10
    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
    Citation Envoyé par guillemouze Voir le message
    C'est très clair. Mais je ne comprends pas pour autant la logique, théoriquement, si une classe implémente une interface IChild, elle implémente forcement IParent, et pourtant, elle support IChild, mais pas IParent ... Y a-t'il une raison a cela ?
    comme dit avant, une Interface est un contrat immuable, si je veux modifier une interface, je dois en créer une nouvelle pour ne pas rompre le précédant contrat.

    exemple
    1er contrat, j'ai la fonction toto
    2eme contrat, j'ai la fonction toto et la fonction titi
    3eme contrat, j'ai toto et tutu (titi est devenu obsolète)
    4eme contrat, j'ai tutu et tata

    comment traduire tout cela ?

    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
    // première version
      IContrat1 = interface
        procedure toto; 
      end;
    // deuxième version, j'enrichie IContrat1
      IContrat2 = interface(IContrat1)
        procedure titi;
      end;
    // troisième version, je laisse tomber titi
      IContrat3 = interface(IContrat1)
        procedure tutu;
      end;
    // quatrième version, je laisse tomber toto
      IContrat4 = interface
        procedure tutu; // c'est la même fonction que dans IContrat3 !
        procedure tata;
      end;
    les interfaces permettent donc de regrouper un ensemble de méthodes données JUSTEMENT sans tenir compte des descendances
    le pseudo héritage permet de ne pas se retaper toute la déclaration précédente

    Notez également que sous Delphi TInterfaceObjet retourne les interfaces qu'il supporte lui-même, mais rien n'empêche de retourner un autre 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
     
    function TObjectFactory.QueryInterface(const IID: TGUID; out Obj): HResult;
    var
      obj: TObject;
    begin
      Result := E_NOINTERFACE;
      if IsEqualGUID(IID, GUID1) then
      begin
        obj := TGUID1Object.Create;
        if obj.GetInterface(IID, Obj) then
          Result := 0
        else
          obj.Free;
     end;
    end;
    techniquement, une interface n'est rien d'autre qu'un tableau de méthodes objet. D'ailleurs je propose dans "Delphi 7 Studio" aux éditions Eyrolles, d'utiliser des interfaces a partir d'un simple record dommage, le livre est épuisé
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  11. #11
    Expert éminent sénior

    Avatar de sjrd
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2004
    Messages
    4 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2004
    Messages : 4 517
    Points : 10 154
    Points
    10 154
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Oui, je sais que "as" c'est un équivalent de Supports\QueryInterface et pas une combinaison de is + cast
    Ce qui me "choquait" était le terme "as designed" est-ce une appellation standard ?
    SJRD a sorti cela comme si c'était une chose naturelle (pour un génie surement) !
    "as designed" est un terme utilisé dans les bug tracking. Tu as "open", "closed", "rejected", etc. et tu as "as designed".

    "as designed" veut dire : "Ce n'est pas un bug, c'est feature. C'est comme ça qu'on l'avait prévu, même si vous, vous croyez que c'est un bug."
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
    Découvrez Mes tutoriels.

  12. #12
    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
    Citation Envoyé par sjrd Voir le message
    "as designed" est un terme utilisé dans les bug tracking. Tu as "open", "closed", "rejected", etc. et tu as "as designed".

    "as designed" veut dire : "Ce n'est pas un bug, c'est feature. C'est comme ça qu'on l'avait prévu, même si vous, vous croyez que c'est un bug."
    WAD ! Works As Designed

    c'est aussi parfois la réponse du support client quand il ne veux pas enregistrer un bug. Par exemple quand c'est fonctionnellement inadapté mais que ça ne sera cependant pas corrigé modifié
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  13. #13
    Rédacteur
    Avatar de omen999
    Profil pro
    Inscrit en
    Février 2006
    Messages
    1 296
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 1 296
    Points : 3 549
    Points
    3 549
    Par défaut
    intéressante discussion, dommage qu'elle parte dans les profondeurs du forum
    nomen omen, nemo non omen - Consultez la FAQ VBScript et les cours et tutoriels VBScript
    le plus terrible lorsqu'une voiture renverse un piéton, c'est que ce sont les freins qui hurlent. (ramón)
    pas de questions techniques par mp

  14. #14
    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
    Tu imagines que le cast sauvage interface vers instance me choque en tant que Delphi habitué au as ne fonctionnant que l'autre un sens ... quoi j'ai vu qu'il était possible (depuis XE ?) de retrouver l'instance d'une interface
    C'est une nouveauté en effet. Par contre je crois que c'est depuis D2010...

    Citation Envoyé par Paul TOTH Voir le message
    c'est aussi parfois la réponse du support client quand il ne veux pas enregistrer un bug. Par exemple quand c'est fonctionnellement inadapté mais que ça ne sera cependant pas corrigé modifié
    A dire vrai, c'est surtout dans ce contexte là que j'ai l'habitude de l'entendre...

  15. #15
    Membre expérimenté Avatar de guillemouze
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    876
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2004
    Messages : 876
    Points : 1 448
    Points
    1 448
    Par défaut
    Citation Envoyé par Paul TOTH Voir le message
    comme dit avant, une Interface est un contrat immuable, si je veux modifier une interface, je dois en créer une nouvelle pour ne pas rompre le précédant contrat.

    exemple
    1er contrat, j'ai la fonction toto
    2eme contrat, j'ai la fonction toto et la fonction titi
    3eme contrat, j'ai toto et tutu (titi est devenu obsolète)
    4eme contrat, j'ai tutu et tata
    Effectivement, en repensant aux interfaces de windows, pour les shell namespace extensions par exemple, on trouve le contrat IExtractIcon, IContextMenu, ... qui heritent juste de IUnknown, et les objets implementent toutes les interfaces nécessaires.
    Moralité, l’héritage des interfaces n'est pas conceptuellement intéressant, une interface = un comportement, et on n'etend pas un comportement, on les combine.

    Merci pour toutes ces infos

  16. #16
    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
    Citation Envoyé par Franck SORIANO Voir le message
    Tu imagines que le cast sauvage interface vers instance me choque en tant que Delphi habitué au as ne fonctionnant que l'autre un sens ... quoi j'ai vu qu'il était possible (depuis XE ?) de retrouver l'instance d'une interface
    C'est une nouveauté en effet. Par contre je crois que c'est depuis D2010...
    et c'est possible tout simplement car 2010 ajoute une interface qui propose la méthode GetInstance si cette interface n'est pas implémentée, c'est que ce n'est pas un objet Delphi pas besoin de D2010 pour le faire, mais D2010 le fait d'office.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  17. #17
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 460
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 460
    Points : 24 874
    Points
    24 874
    Par défaut
    Citation Envoyé par guillemouze Voir le message
    Moralité, l’héritage des interfaces n'est pas conceptuellement intéressant, une interface = un comportement, et on n'etend pas un comportement, on les combine
    +1

    C'est aussi la conclusion à laquelle je suis arrivé pour mes Interfaces avec GUID !
    De toute façon c'est confirmé dans les Cours, j'ai lu Technique : Travailler avec les Interfaces en C++Builder Partie 1, j'ai demandé DjmSoftware, où en était la Partie 2, il m'a dit qu'elle n'existait pas faute de succès de la 1ère
    J'aurais du lire
    Les interfaces d'objet sous Delphi : 16. Interroger l'arbre d'héritage d'une interface qui confirme les limites du Supports !
    Surtout qu'en C++, j'ai des Warnings :
    Avec les options par défaut
    En 2007 : W8024: La classe de base 'classe1' est aussi une classe de base de 'classe2' (C++)
    En XE : W8130 L'interface '%s' ne dérive pas de IUnknown. (Les interfaces doivent dériver de IUnknown) (C++)
    On sent qu'entre les deux versions, il y a eu des choix technique pour guider le développeur C++ vers le DelphiInterface à la place des Virtuelles Pures !

    Citation Envoyé par Paul TOTH Voir le message
    et c'est possible tout simplement car 2010 ajoute une interface qui propose la méthode GetInstance si cette interface n'est pas implémentée, c'est que ce n'est pas un objet Delphi pas besoin de D2010 pour le faire, mais D2010 le fait d'office.
    D'accord mon ItSelf de 2004 (en fait c'était en 2004 pas 2003) est donc la même chose que ce GetInstance, une fonction renvoyant Self ! Comme quoi, ce que je jugais vilain ne l'était pas tant que cela !

    Sur le Doc Wiki Embarcadero, je ne trouve pas de documentation sur ce GetInstance ! As-tu un article sur "Comment retrouver l'instance d'une interface"
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  18. #18
    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
    Citation Envoyé par ShaiLeTroll Voir le message
    Sur le Doc Wiki Embarcadero, je ne trouve pas de documentation sur ce GetInstance ! As-tu un article sur "Comment retrouver l'instance d'une interface"
    je n'ai pas de Delphi suffisamment récent pour tester, mais ce n'est pas forcément documenté de la sorte

    on en parle ici aussi
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  19. #19
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 460
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 460
    Points : 24 874
    Points
    24 874
    Par défaut
    Euh, un peu hardcore tes deux liens

    J'avais oublié d'éditer ma réponse mais j'avais trouvé la rubrique :

    Références d'interfaces (Delphi) - Transtypage des références d'interfaces en objets

    c'est les opérateurs is et as qui font le boulot, donc normal que je ne voyais pas de méthode GetInstance dans system.pas and co !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

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

Discussions similaires

  1. Interface, héritage et méhode toString
    Par _Von_ dans le forum Langage
    Réponses: 4
    Dernier message: 13/11/2014, 19h10
  2. [DELPHI] Interface Delphi 7 / Oracle 8i
    Par kifout23 dans le forum Interfaces de programmation
    Réponses: 4
    Dernier message: 28/04/2008, 09h40
  3. Réponses: 6
    Dernier message: 08/02/2008, 14h58
  4. interfacer Sage commerciale avec delphi
    Par sir_ben dans le forum Bases de données
    Réponses: 4
    Dernier message: 14/07/2006, 09h24
  5. Interface non supportée
    Par Amara dans le forum Langage
    Réponses: 14
    Dernier message: 16/07/2004, 13h18

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