……省略废话若干……
Delphi的泛型在C++中被暴露为模板。然而很重要的一点是它的真正实例化于 Delphi 那边,而不是C++。所以,你只能使用那些 Delphi 代码中已经显式实例化的模板类型。例如,我们声明一个 Delphi 中的简单泛型 TList<T>:
unit DelphiUnit; interface uses System.Generics.Collections; type MyTList<T> = class(TList<T>) public // Anchors constructor/destructor constructor Create; destructor Destroy; override; class procedure Cleanup(var L: MyTList<T>); static; end; // DoubleList: instantiates MyTList<double> DoubleList = class(MyTList<double>) end; // StringList: instantiates MyTList<string> StringList = class(MyTList<string>) end; implementation class procedure MyTList<T>.Cleanup(var L: MyTList<T>); begin L.Free; end; constructor MyTList<T>.Create; begin inherited; end; destructor MyTList<T>.Destroy; begin inherited; end; end.
上面的接口在 C++ 中将暴露为:
// CodeGear C++Builder // Copyright (c) 1995, 2012 by Embarcadero Technologies, Inc. // All rights reserved // (DO NOT EDIT: machine generated header) 'DelphiUnit.pas' rev: 24.00 (Windows) #ifndef DelphiunitHPP #define DelphiunitHPP #pragma delphiheader begin #pragma option push #pragma option -w // Display all warnings #pragma option -w-inl // Functions %s are not expanded inline #pragma option -w-8111 // Accessing deprecated entity #pragma option -Vx // Zero-length empty class member #pragma pack(push,8) #include <System.hpp> // Pascal unit #include <SysInit.hpp> // Pascal unit #include <System.Generics.Collections.hpp> // Pascal unit #include <System.Generics.Defaults.hpp> // Pascal unit #include <System.Types.hpp> // Pascal unit //-- user supplied ----------------------------------------------------------- namespace Delphiunit { //-- type declarations ------------------------------------------------------- template<typename T> class DELPHICLASS MyTList__1; // Template declaration generated by Delphi parameterized types is // used only for accessing Delphi variables and fields. // Don't instantiate with new type parameters in user code. template<typename T> class PASCALIMPLEMENTATION MyTList__1 : public System::Generics::Collections::TList__1<T> { typedef System::Generics::Collections::TList__1<T> inherited; public: __fastcall MyTList__1(void); __fastcall virtual ~MyTList__1(void); static void __fastcall Cleanup(MyTList__1<T>* &L); }; class DELPHICLASS DoubleList; class PASCALIMPLEMENTATION DoubleList : public MyTList__1<double> { typedef MyTList__1<double> inherited; public: /* {DelphiUnit}MyTList<System_Double>.Create */ inline __fastcall DoubleList(void) : MyTList__1<double>() { } /* {DelphiUnit}MyTList<System_Double>.Destroy */ inline __fastcall virtual ~DoubleList(void) { } }; class DELPHICLASS StringList; class PASCALIMPLEMENTATION StringList : public MyTList__1<System::UnicodeString> { typedef MyTList__1<System::UnicodeString> inherited; public: /* {DelphiUnit}MyTList<System_string>.Create */ inline __fastcall StringList(void) : MyTList__1<System::UnicodeString>() { } /* {DelphiUnit}MyTList<System_string>.Destroy */ inline __fastcall virtual ~StringList(void) { } }; //-- var, const, procedure --------------------------------------------------- } /* namespace Delphiunit */ #if !defined(DELPHIHEADER_NO_IMPLICIT_NAMESPACE_USE) && !defined(NO_USING_NAMESPACE_DELPHIUNIT) using namespace Delphiunit; #endif #pragma pack(pop) #pragma option pop #pragma delphiheader end. //-- end unit ---------------------------------------------------------------- #endif // DelphiunitHPP
C++ 代码链接上面的 Delphi 单元产生的 .obj 就可以使用 MyTList__1<double>
或 MyTList__1<System::String> 实例。
void UseDLists() { // C++ code can use the Generics defined in Delphi directly // as long as the C++ code limits itself to types for which // the generic was instantiated on the Delphi side. For example, // since the Delphi Unit instantiates MyTList<String> // and MyTList<double> we can use these here. // However, if we try to use MyTList__1<char> we'll get // errors since the Delphi side did not instantiate // MyTList<AnsiChar>. MyTList__1<double>* dblList = new MyTList__1<double>(); dblList->Add(1.0); dblList->Add(1.5); double d = dblList->Items[1]; #ifdef _WIN64 delete dblList #else MyTList__1<double>::Cleanup(dblList); #endif MyTList__1<System::String> *strList = new MyTList__1<System::String>(); strList->Add("First"); strList->Add("Second"); strList->Add("Third"); assert(strList->Count == 3); System::String str = strList->Items[0]; assert(str == "First"); assert(strList->Items[1] == "Second"); assert(strList->Items[2] == "Third"); strList->Insert(0, "Inserted"); assert(strList->Count == 4); assert(strList->Items[0] == "Inserted"); assert(strList->Items[1] == "First"); strList->Reverse(); assert(strList->Items[0] == "Third"); assert(strList->Items[1] == "Second"); assert(strList->Items[2] == "First"); assert(strList->Items[3] == "Inserted"); assert(strList->Contains("Inserted")); assert(!strList->Contains("Not Inserted")); strList->Sort(); strList->Remove("Inserted"); assert(strList->Items[0] == "First"); assert(strList->Items[1] == "Second"); assert(strList->Items[2] == "Third"); #ifdef _WIN64 delete strList; #else MyTList__1<System::String>::Cleanup(strList); #endif }
如果你的 C++ 代码尝试使用一个没有实例化的 Delphi 泛型,你将在链接时得到错误提示。例如下面的代码尝试使用Delphi 代码中没有明确实例化为 MyTList<AnsiChar> 的 MyTList__1<char> :
void UseListOfChar() { MyTList__1<char>* charList = new MyTList__1<char>(); charList->Add('a'); // ... }
当上面的代码编译后,在链接时将报告下面的错误:
[ilink32 Error] Error: Unresolved external 'Delphiunit::MyTList__1<char>::' referenced from CPPUNIT.OBJ [ilink32 Error] Error: Unresolved external '__fastcall Delphiunit::MyTList__1<char>::MyTList__1<char>()' referenced from CPPUNIT.OBJ [ilink32 Error] Error: Unresolved external '__fastcall System::Generics::Collections::TList__1<char>::Add(const const char)' referenced from CPPUNIT.OBJ [ilink32 Error] Error: Unable to perform link
要解决这个问题,在 Delphi 中声明类型 TMyList<AnsiChar>。