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("");
 
  // ----
 
}
//---------------------------------------------------------------------------