Comment gérer les génériques Delphi dans C++

De RAD Studio (Français)

Remonter à Gestion des fonctionnalités Delphi dans C++Builder 2009 - Index

Cette rubrique décrit quelques problèmes de programmation que vous pourriez rencontrer avec les génériques, une des nouvelles fonctionnalités de Delphi.

Les génériques Delphi sont exposés dans C++ comme des templates. Toutefois, il est important de réaliser que les instanciations surviennent du côté Delphi, pas dans C++. Par conséquent, vous pouvez seulement utiliser ces templates pour les types qui étaient instanciés explicitement dans le code Delphi. Par exemple, déclarons un simple générique, TList<T>, dans Delphi :


 interface

type

    MyTList<T> = class(TList<T>) // TList est une classe de l'espace 
                                  // de nommage Generics.Collections
        FItems: array of T;
    protected
        function GetLength: Integer;
    public
        function Get(Index: Integer): T;
    published
        property Len: Integer read GetLength;
    end;

    { ScoreList dérivé d'un TList<double>}
    ScoreList = class(MyTList<double>)
    end;
    { StringList dérivé d'un TList<string>}
    StringList = class(MyTList<string>)
    end;

implementation

{$R *.dfm}

function MyTList<T>.GetLength: Integer;
begin
    Result := Count;
end;

  function MyTList<T>.Get(Index: Integer): T;
begin
    Result := Items[Index];
end;

L'interface ci-dessus est exposée dans C++ comme suit :


// La déclaration de template générée par les types paramétrés de Delphi
// est utilisée pour accéder aux champs et variables de Delphi.
// N'instanciez pas avec les nouveaux paramètres de type dans le code utilisateur.
template<typename T> class PASCALIMPLEMENTATION 
   MyTList__1 : public Generics_collections::TList__1<T>
{
typedef Generics_collections::TList__1<T> inherited;

private:
typedef DynamicArray<T> _MyTList__1__1;

public:
    _MyTList__1__1 FItems;

 protected:
    int __fastcall GetLength(void);

public:
    T __fastcall Get(int Index);

__published:
    __property int Len = {read=GetLength, nodefault};
public:
/* TList<T>.Create */ inline __fastcall MyTList__1(void)
   /* overload */ : Generics_collections::TList__1<T>() { }
/* TList<T>.Destroy */ inline __fastcall virtual ~MyTList__1(void) { }

};

class DELPHICLASS ScoreList;
class PASCALIMPLEMENTATION ScoreList : public MyTList__1<double>
{
typedef MyTList__1<double> inherited;

public:
/* TList<Double>.Create */ inline __fastcall ScoreList(void)
   /* overload */ : MyTList__1<double>() { }
/* TList<Double>.Destroy */ inline __fastcall virtual ~ScoreList(void) { }

};

class DELPHICLASS StringList;
class PASCALIMPLEMENTATION StringList : public MyTList__1<System::UnicodeString>
{
typedef MyTList__1<System::UnicodeString> inherited;

public:
/* TList<string>.Create */ inline __fastcall StringList(void)
   /* overload */ : MyTList__1<System::UnicodeString>() { }
/* TList<string>.Destroy */ inline __fastcall virtual ~StringList(void) { }

};

La liaison du code C++ avec le fichier .obj créé à partir de l'unité Delphi ci-dessus peut utiliser des instances de TList__1<double> ou ScoreList.

void UseScoreList()
{
  ScoreList* list = new ScoreList();

  list->Add(1.0);
  list->Add(2.0);

  int len = list->Len;
  assert(len == 2);

  delete list;
}

void UseTList__1()


{
    // Le code C++ peut utiliser les génériques définis directement dans Delphi
    // tant que le code C++ se limite lui-même aux types pour lesquels
    // le générique était instancié sur la taille Delphi. Par exemple,
    // puisque test.pas utilise TList<String> et TList<double>, vous pouvez utiliser
    // ceci ici. Toutefois, si nous tentons d'utiliser TList__1>char>, nous obtiendrons
    // une erreur car le côté Delphi n'instanciait pas
    // TList<AnsiChar>.
    TList__1<double>* dblList = new MyTList__1<double>();
    dblList—>Add(1.0);
    dblList—>Add(1.5);
    double d = dblList—>Get(1);
    delete dblList;

    MyTList__1<UnicodeString> *stringList = new MyTList__1<UnicodeString>();
    stringList->Add("hiya");
    stringList->Add("there");
    stringList->Add("buckeroo");
    UnicodeString dstring = stringList->Get(0);
    delete stringList;
 }

Si le code C++ tente d'utiliser un générique Delphi pour les types qui n'étaient pas instanciés dans Delphi, vous obtiendrez des erreurs lors de la liaison. Par exemple, le code suivant tente d'utiliser TList__1<char> quand le code Delphi n'instanciait pas explicitement TList<AnsiChar> :

void UseListOfChar()
{
  TList__1<char>* charList = new TList__1<char>();
charList->Add('a');
  char ch = charList->Get(1);
  delete charList;
}

Tandis que le code ci-dessus est correctement compilé, les erreurs suivantes sont générées lors de la liaison :

[Erreur ILINK32] Erreur : Unresolved external 
       'Test::MyTList__1<char>::>::' référencé depuis USETEST.OBJ
[Erreur ILINK32] Erreur : '__fastcall 
        Test::MyTList__1<char>>::Add(char)' externe non résolu, référencé depuis USETEST.OBJ
[Erreur ILINK32] Erreur : '__fastcall 
       Test::MyTList__1<char>::Get(int)' externe non résolu, référencé depuis USETEST.OBJ

Pour éliminer l'erreur, assurez-vous que le code Delphi utilise le type MyTList<AnsiChar>.

Voir aussi

Autres langues