天天看點

BCB中的RTTI機制

BCB中的RTTI機制

RTTI在BCB中其實有兩個意義。首先,針對一般标準的C++中所定義的,RTTI是所謂的Run-Time Type Identification的縮寫。傳統的程式語言中,所謂的資料型态僅在Compile-Time有所作用。舉例而言,您宣告了一個變量a,并且指定其型态為整數。您如何在Run-Time期間知道他的型态是整數呢?很遺憾的是,在原來的C/C++中您是無法知道這樣的事情的。或者會問,這樣的資訊有何作用?若是您考慮對象的繼承關系,您就會發現其重要性了。

舉例而言,若您有下面的程式:

class CShape {

    …

    public:

        virtual void ShowMe() = 0; // Virtual function

} ;

class CRectangle {

        void ShowMe();

};

viod Show(CShape *someShape) {

    someShape->ShowMe();

}

int main(void) {

    CRectangle myRect ;

    Show(&myRect);

    CNotShape notShape ;

    Show(&notShape); // Error!!

    上面的程式中CShape為base class。而CRectangle繼承它。是以,在main function中的第一個Show()可以正常動作,因為在Show()中,someShape->ShowMe()可以正确的找到在 CRectangle的ShowMe()函式。可是第二個Show()就會有問題,原因在于CNotShape并非繼承于CShape,是以沒有 ShowMe()的函式可用。是以,會造成Access Violation的狀況發生。或者會覺得這種狀況不會發生在您身上,但是請想想如果您是連結庫的設計者,您如何可確定使用者不會随便指定奇怪的對象給您呢?是以如果能夠在執行期判斷傳進的對象真正的型态以及其繼承關系,就可以直接判斷傳入的對象可否使用。否則便傳回錯誤。這樣便可避免Access Violation的問題。能夠提供這個解決方法的便是所謂的C++的RTTI機制了。

不過,C++ RTTI機制的功能十分有限。例如,想要進一步的列舉出class所擁有的成員及函式,在Run-Time是無法做到的。因為C++ RTTI僅是一個Identification機制,用來識别型态及其繼承關系。并不包含其完整型态資訊。這時,您需要引進VCL所獨有的RTTI機制。在VCL中的RTTI指的是Run-Time Type Information機制。由于是由VCL所提供的RTTI機制,是以僅适用于繼承在TObject之上的類别或對象,其它類别或對象并不适用。

由VCL所提供的RTTI機制,可以讓您清楚的資料類别的資訊,對象的資訊,以及列舉出所包含的成員及函式。不過,在好用的背後是要付出代價的。對象的資訊需要地方來儲存,這會造成而額外的記憶體以及檢查這些資訊的CPU時間的浪費。不過就今日CPU及記憶體的價格,與RTTI所帶來的友善性相較之下,這些額外的浪費就顯得微不足道了。而Borland在這方面也下了不少奶牷A關于這方面的程式代碼大部分皆以彙編語言寫成,是以處理速度很快。

以下将針對這兩種RTTI分别做說明。

C++中的RTTI機制

如果您翻閱C++ Builder所附的On-Line Help,您可找到下面這段對于RTTI的說明:

Runtime type identification (RTTI) lets you write portable code that can determine the actual type of a data object at runtime even when the code has access only to a pointer or reference to that object. This makes it possible, for example, to convert a pointer to a virtual base class into a pointer to the derived type of the actual object. Use the dynamic_cast operator to make runtime casts.

The RTTI mechanism also lets you check whether an object is of some particular type and whether two objects are of the same type. You can do this with typeid operator, which determines the actual type of its argument and returns a reference to an object of type const type_info, which describes that type.

You can also use a type name as the argument to typeid, and typeid will return a reference to a const type_info object for that type. The class type_info provides an operator== and an operator!= that you can use to determine whether two objects are of the same type. Class type_info also provides a member function name that returns a pointer to a character string that holds the name of the type.

正如上面所說的,您可透過typeid()運算子來取得type_info的資訊。此處應當注意的是typeid()是一個運算子。他與sizeof() 是相同等級的運算子。不過,若要使用typeid()您需要include typeinfo這個項目。您的include寫法如下:

#include <typeinfo>

using namespace std;

透過typeid()我們可以取得特定的型态的資訊。例如,想要比較兩個變量是否為相同型态。您可以寫成下面的形式:

template <class T, class D>

bool isSameType(T var1, D var2)

{

    return (typeid(var1) == typeid(var2));

這個函式可用來比較兩個變量的型态是否相等。

若您想取得型态的名稱。您可使用typeid()所傳回來的型态的name()函式。例如:

int a;

ShowMessage(typeid(int).name());

ShowMessage(typeid(a).name());

    若您想确認兩者之間有無繼承關系,可使用typeid()所傳回來的型态中的before()函式。before()函式中有一個參數也是一個由 typeid()所傳回的型态資訊。以前面的例子來說,若您想切确知道CShape是否在CRectangle之前(也就是是否CRectangle為 CShape的祖先),可用下面的程式來判斷:

if( typeid(CShape).before(typeid(CRectangle)) )

    return true ;

    是以,當您想要對一個class進行up casting或是down casting時,可先用這種方式判斷一下,兩者是否有繼承關系,然後才進行轉換。當然,這樣的檢查常常會用到,是以你可能打算把他寫成一個工具函式來用。不過,先等一下!标準的C++已經幫您準備好了!而且不隻一個,C++準備了四個casting的工具函式,每一個都有不同的用法及意義。他們分别是:

const_cast<Type>(var)

const_cast是一個compile time的cast。其主要作用為移除或加上型态的 const 限制。舉例來說,您有一個const的整數a。您想要用一個整數名額指向它。

    const i = 0;

    int *p = &i ; // Compile error! Cannot cast from const to violate.

但是您可能非常确定自己想要做什麼,是以您可使用const_cast明确的告訴compiler做您要求的動作。

    int *p = const_cast<int *>(&i) ; // OK.

同樣的,要把不具const性質的型态轉成const性質也是相同的方法。不過,請務必要知道自己為何這樣做,否則可能會惹上麻煩。

dynamic_cast<Type>(ptr)

在使用dynamic_cast時,Type必需為指定為一個class的名額,否則就必需是void *。若為void *,則ptr所給定的名額将會被轉換為void *,并且任何型态的指針内。然而,真正常用的是用來進行class的up casting或down casting。以前面的CShape及CRectangle而言,您可使用下面的方式進行轉換:

    CShape *sp = dynamic_cast<CShape *>( some_pointer );

    CRectangle *rp = dynamic_cast<CRectangle *>(some_pointer);

或許,上面的範例看起來跟一般的static casting沒有什麼差别。其實,差别十分大,我們知道static casting的意思有點類似于強制要求compile幫您進行轉換,是以不會顧形态與形态之間本身是否有繼承關系、是否真的可以轉換。是以稍不注意就常常會有Access Violation的狀況。但是dynamic_cast就不一樣了,他會幫您檢查并且确定來源的型态與目的型态是可進行轉換的。若不能轉換就會傳回 NULL。是以您可以依據dynamic_cast的傳回值來判斷是否轉換成功。

reinterpret_cast<Type>(var)

其中Type必需為pointer, reference, arithmetic type, pointer to function或是pointer to member。reinterpret_cast可以幫您将整數轉變為一個指向某種型态的指針。主要用于當位址必處理放置于整數變量中。要将他轉回原來型态的指針時所使用。

static_cast<Type>(var)

就是我們一般以前常用的static casting的形式。隻是為了與前面所介紹的三種casting比對,而改成了這種形式。是以若您以前常用如下的方式進行casting,不妨換種方式:

    int a ;

    float b = 10.01

    a = static_cast<int>(b);

不确定轉換的名額會不會與轉換後指針的型态相容時,請多多使用dynamic_cast。這樣可以避免預想不到的狀況發生。

VCL的RTTI機制

VCL所提供的RTTI機制,可以提供非常詳盡的資訊。其大部分都供Borland C++ Builder或Delphi的Design環境使用。這也就是為何在Object Inspector可以看到對象的屬性(Property)及設定其Event了。隻要您掌握了VCL上RTTI的精髓,您也可以寫出Object Inspector一樣的功能。

所謂的RTTI可視為用來記錄型态資訊的一個Structure。這個部分是由VCL所提供。是以,要使用這些RTTI機制,大部分的狀況下必需作用于繼承自TObject的VCL元件。

我們要如何取得這個記載着型态資訊的Structure呢?有幾種方式:

方法一

要取得一個VCL元件類别的資訊可透過其ClassInfo()這個method。如果您看過VCL的對象階層圖,您就知道ClassInfo()這個 method是在TObject内定義的。是以,所有的VCL元件都可以使用他。仔細看一下Borland所附的On-Line Help;

Returns a pointer to the runtime type information (RTTI) table for the object type.

typedef TMetaClass* TClass;

static void * __fastcall ClassInfo(TClass cls);

void * __fastcall ClassInfo(){return ClassInfo(ClassType()); }

Description

Use ClassInfo to access the RTTI table that contains information about the object type, its ancestor type, and all of its published properties.

Call ClassInfo with no arguments to obtain the RTTI table for a specific object instance. Call the static TObject::ClassInfo method, passing the metaclass information, to obtain the RTTI table for a class of object when you don’t have an instance.

RTTI is used internally by the development environment. ClassInfo is rarely called directly in an application. TObject includes other methods that provide easier access to RTTI.

ClassInfo其實有兩個,一種是TObject::ClassInfo()。另外一個是獨立的static function。其中,第一種适用于已經有确定的instance。而在沒有instance的狀況下,就應當使用static function的方式。或者要問如何得到對應某個class的TClass資訊呢?您需要搭配VCL所提供的__classid這個關鍵詞。他可以取得特定class的TClass資訊。例如:要取得TButton的RTTI資訊,您需要使用下面的方式:

ClassInfo(__classid(TButton));

我們也看到ClassInfo()的傳回值是一個void *,這就是指向記載着RTTI資訊結構的指針。

除了ClassInfo(),其實還有另外一個方式,就是使用__typeinfo()這個宏。這個宏與ClassInfo()的作用相同。唯一的差别在于ClassInfo()傳回的是一個void *,而__typeinfo()會經過一次的casting動作轉成PTypeInfo的型态,也就是TTypeInfo *的型态。

方法二

很不幸的一點,前述的方式僅針對VCL的類别有作用。如果不是VCL類别就會有問題了。例如,某些類别看來很像VCL類别,實際上僅是一個列舉型态。就像是TAlign這個用來指定元件放置行為的型态。雖然也是T開頭。實際上不過就是個列舉型态罷了。是以,前面的方式都會讓您得到 compile error。在Delphi中,有一個名為TypeInfo的函式可以取得各種型态的TTypeInfo資料。但是,他主要的運作是在compile time。這也就是說,你必需在compile time就指定好型态。是以,在BCB中的實用性不大。如果真的有必要。可以另外寫一個Delphi的程式檔案,專門利用TypeInfo函式取得 TTypeInfo的資料。關于這個部分,建議您參考後面所提的『Run-Time Type Information(RTTI) In C++ Builder 5』一文。

方法三

如果您要存取的是非VCL類别的型态,您可能要參考上面第二點的作法。不過,如果您要存取的是屬于某個VCL類别的__published節中的非 VCL類别型态。那麼恭喜您!您未必需要搭配Delphi了。例如:您要取得TAlign這個型态的資訊。所幸,在TPanel這個VCL元件中的 Align屬性就是TAlign的型态。而且Align是__published的。因為VCL對于__published内的東西一律會産生其RTTI 詳細資訊。是以,我們就可以透過這種方式來存取TAlign的RTTI資訊了。用法如下:

#include <typinfo .hpp> // Note: it is “typinfo”, not “typeinfo”

    PPropInfo pp = GetPropInfo(__typeinfo(TPanel), "Align") ;

    PTypeInfo pt = ((pp==NULL)? NULL : *(pp->PropType));

VCL RTTI有何資訊?

C++本身的RTTI用途蠻容易了解的,但是VCL的RTTI呢?取得他的TTypeInfo 資訊後有何作用呢?

其實,秘密都藏在$(BCB)\Source\VCL\typinfo.pas中。在這個檔案中存放了許多與VCL RTTI相關的資訊及程式代碼。如果您對于Delphi或是Object Pascal不熟悉,沒關系,看看$(BCB)\Include\VCL\typinfo.hpp。這個是由BCB所自動産生出來的include檔案。雖然沒有程式代碼在内。但是,光看裡面的定義,也大概可以猜出其作用為何。在此,我們将針對這個檔案内所提供的資料結構及相關函式進行說明。

首先,我們來看看前面一直提到的TTypeInfo這個structure。您可在typinfo.hpp中找到他的定義。

struct TTypeInfo

    TTypeKind Kind;

    System::ShortString Name;

這個結構非常簡單,隻有兩個項目,其中TTypeKind是一個列舉型态。Kind記錄這是何種的型态。而Name則記載了該型态的名字。在VCL中針對TTypeKind的列舉型态,共有下面這些項目:

列舉值 說明 

tkUnknown         保留,未使用的值。 

tkInteger         整數 

tkChar          Char或是AnsiChar的型态 

tkEnumeration      列舉型态,包含Boolean, ByteBool, WordBool, LongBool及Bool 

tkFloat          浮點數 

tkString ShortString   型态 

tkSet Set         型态 

tkClass            類别型态 

tkMethod          Procedure或是function型态 

tkWChar           WideChar 型态 

tkLString            WideString型态 

tkVariant          Variant型态 

tkArray           Array型态 

tkRecord          Record型态(即struct) 

tkInterface          Interface型态 

tkInt64           Int64型态 

tkDynArray       動态數組型态(即DynamicArray) 

    或許您會覺得奇怪,怎麼好像一堆沒看過的型态。其實,這些對應的值都是Delphi中的型态。是以,您需要測試一下看看在BCB中,哪些型态會對應到上面的項目。

有了上面這個資訊,您就可以取得在VCL的型态資訊,并且藉此來判斷所取得的型态為何。當然未必所有的型态都可用Kind來加以判斷,此時建議您搭配Name一起來加以判斷,相信就可清楚的判斷出您要的型态了。

實際上,光是TTypeInfo的内容是不夠用的,因為他是所有型态共同的部分,針對其它屬于型态相關的資訊,在TTypeInfo中是看不到的。若需要取得這些與個别型态相關的資訊,就需要用到在TypInfo.hpp後面所記載的一些工具函式。首先,最重要的工具函式就是:

PTypeData __fastcall GetTypeData(PTypeInfo TypeInfo);

這個函式的參數為一個指向TTypeInfo的名額,透過這個TTypeInfo的資訊,會傳回另一個指向TTypeData的名額。這就是我們所要的個别型态的詳細資料。不幸的是,如果您去查鋁ypInfo.hpp中的訊息,您會發現到TTypeData其實是一堆struct的聯集。主要是因為不同的型态所需記錄的東西不同所緻。

前面我們曾經提到透過BCB我們可以取得放在__published部分的屬性資料。那麼,我們可以取得所有屬性的清單嗎?答案是可以的,隻要他是放在__published中。要取得這個資訊,您需要透過一些在TypInfo.hpp中所定義的函式的幫助。主要有幾個函式能夠幫助我們取得屬性的資訊他們分别是:

extern PACKAGE PPropInfo __fastcall GetPropInfo(System::TObject*

         Instance, const AnsiString PropName, TTypeKinds AKinds =

         System::Set<TTypeKind, tkUnknown, tkDynArray> () );

extern PACKAGE PPropInfo __fastcall GetPropInfo(TMetaClass* AClass,

         const AnsiString PropName, TTypeKinds AKinds =

extern PACKAGE PPropInfo __fastcall GetPropInfo(PTypeInfo TypeInfo, const AnsiString PropName);

extern PACKAGE PPropInfo __fastcall GetPropInfo(PTypeInfo TypeInfo, const AnsiString PropName, TTypeKinds AKinds);

extern PACKAGE void __fastcall GetPropInfos(PTypeInfo TypeInfo, PPropList PropList);

extern PACKAGE int __fastcall GetPropList(PTypeInfo TypeInfo, TTypeKinds TypeKinds, PPropList PropList, bool SortList = true);

extern PACKAGE int __fastcall GetPropList(PTypeInfo TypeInfo, /* out */ PPropList &PropList);

extern PACKAGE int __fastcall GetPropList(System::TObject* AObject, /* out */ PPropList &PropList);

    簡單的說,如果你已經很切确的知道自己所要找的是某個屬性,就請用GetPropInfo。如果您希望取得所有的屬性,可以使用GetPropInfos函式。如果您希望隻取得屬于某種型态的屬性,或是對所取得的屬性進行排序,建議使用GetPropList函式。

舉例來說,如果您要取得Form1中的Align屬性的型态資訊。您可使用如下的程式代碼:

PPropInfo pi ;

pi = GetPropInfo(Form1->ClassInfo(), "Align");

若您希望取得某個VCL元件的所有屬性,可使用

TPropList List;

GetPropInfos(Form1->ClassInfo(),(PPropList)&List);

如果您想取得符合某些特定型态的屬性,可用:

int Count = GetPropList((PTypeInfo)(Form1->ClassInfo()), tkAny, (PPropList)&List);

不過這裡有個問題,如果您去看一下TPropList的定義,會發現他其實是一個非常大的指針數組。這樣記憶體是蠻浪費的,是以建議您可以換種方式:

int count = GetPropList((PTypeInfo)(Form1->ClassInfo()), tkAny, NULL);

PPropList list = new PPropInfo[count];

try {

    GetPropList((PTypeInfo)ClassInfo(), tkAny, list);

__finally {

    delete [ ] list ;

其中,TTypeKinds是用來記錄您期望符合的型态。他是一個Set的型态。舉例來說,如果您要取得整數,浮點數這兩種型态。在TTypeKinds的部分可用下面的形式:

TTypeKinds() << tkInteger << tkFloat ;

如果您是BCB 5的使用者,這裡請您要注意了,BCB 5在這個地方似乎有點問題,也就是說他的typinfo.hpp在這個地方的定義是錯的。正确的定義應該是下面這樣的:

#define tkAny (System::Set<TTypeKind, tkUnknown, tkDynArray> ()\

         << TTypeKind(0) << TTypeKind(1) << TTypeKind(2)\

         << TTypeKind(3) << TTypeKind(4) << TTypeKind(5)\

         << TTypeKind(6) << TTypeKind(7) << TTypeKind(8)\

         << TTypeKind(9) << TTypeKind(10) << TTypeKind(11)\

         << TTypeKind(12) << TTypeKind(13) << TTypeKind(14)\

         << TTypeKind(15) << TTypeKind(16) << TTypeKind(17) )

#define tkMethods (System::Set<TTypeKind, tkUnknown, tkDynArray> () << TTypeKind(8) )

#define tkProperties (System::Set<TTypeKind, tkUnknown,\

         tkDynArray> () << TTypeKind(1) << TTypeKind(2) << \

         TTypeKind(3) << TTypeKind(4) << TTypeKind(5) << \

         TTypeKind(6) << TTypeKind(7) << TTypeKind(9) << \

         TTypeKind(10) << TTypeKind(11) << TTypeKind(12) << \

         TTypeKind(13) << TTypeKind(14) << TTypeKind(15) << \

         TTypeKind(16) << TTypeKind(17) )

    奇怪的是,在BCB 4之前與BCB 6都是正确的,僅在BCB 5是錯的。建議您手動将typinfo.hpp更正過來。

當取得我們所要的屬性後,接下來的動作就是要存取其屬性值。舉例來說,如果要設定某個bool型态的屬性為true,或者是取得其現在的屬性,該如何做呢?本來這是十分複雜的步驟,不過因為typinfo.hpp中提供了不少好用的函式,是以我們可以很輕易的存取這些屬性值了。這些友善的函式及其定義與說明如下:

判斷是否為__published的屬性:

extern PACKAGE bool __fastcall IsPublishedProp(System::TObject* Instance, const AnsiString PropName);

extern PACKAGE bool __fastcall IsPublishedProp(TMetaClass* AClass, const AnsiString PropName);

extern PACKAGE bool __fastcall IsStoredProp(System::TObject* Instance, const AnsiString PropName);

extern PACKAGE bool __fastcall IsStoredProp(System::TObject* Instance, PPropInfo PropInfo);

取得與比較屬性的型态:

extern PACKAGE bool __fastcall PropIsType(System::TObject* Instance, const AnsiString PropName, TTypeKind TypeKind);

extern PACKAGE bool __fastcall PropIsType(TMetaClass* AClass, const AnsiString PropName, TTypeKind TypeKind);

extern PACKAGE TTypeKind __fastcall PropType(System::TObject* Instance, const AnsiString PropName);

extern PACKAGE TTypeKind __fastcall PropType(TMetaClass* AClass, const AnsiString PropName);

存取屬性(不管型态):

extern PACKAGE Variant __fastcall GetPropValue(System::TObject* Instance, const AnsiString PropName, bool PreferStrings = true);

extern PACKAGE void __fastcall SetPropValue(System::TObject* Instance, const AnsiString PropName, const Variant &Value);

存取整數型态屬性:

extern PACKAGE int __fastcall GetOrdProp(System::TObject* Instance, const AnsiString PropName);

extern PACKAGE void __fastcall SetOrdProp(System::TObject* Instance, const AnsiString PropName, int Value);

extern PACKAGE int __fastcall GetOrdProp(System::TObject* Instance, PPropInfo PropInfo);

extern PACKAGE void __fastcall SetOrdProp(System::TObject* Instance, PPropInfo PropInfo, int Value);

存取浮點數型态屬性:

extern PACKAGE Extended __fastcall GetFloatProp(System::TObject* Instance, const AnsiString PropName);

extern PACKAGE void __fastcall SetFloatProp(System::TObject* Instance, const AnsiString PropName, const Extended Value);

extern PACKAGE Extended __fastcall GetFloatProp(System::TObject* Instance, PPropInfo PropInfo);

extern PACKAGE void __fastcall SetFloatProp(System::TObject* Instance, PPropInfo PropInfo, const Extended Value);

存取列舉型态屬性:

extern PACKAGE AnsiString __fastcall GetEnumProp(System::TObject* Instance, const AnsiString PropName);

extern PACKAGE void __fastcall SetEnumProp(System::TObject* Instance, const AnsiString PropName, const AnsiString Value);

extern PACKAGE AnsiString __fastcall GetEnumProp(System::TObject* Instance, PPropInfo PropInfo);

extern PACKAGE void __fastcall SetEnumProp(System::TObject* Instance, PPropInfo PropInfo, const AnsiString Value);

extern PACKAGE AnsiString __fastcall GetEnumName(PTypeInfo TypeInfo, int Value);

存取集合型态屬性:

extern PACKAGE AnsiString __fastcall GetSetProp(System::TObject* Instance, const AnsiString PropName, bool Brackets = false);

extern PACKAGE void __fastcall SetSetProp(System::TObject* Instance, const AnsiString PropName, const AnsiString Value);

extern PACKAGE AnsiString __fastcall GetSetProp(System::TObject* Instance, PPropInfo PropInfo, bool Brackets = false);

extern PACKAGE void __fastcall SetSetProp(System::TObject* Instance, PPropInfo PropInfo, const AnsiString Value);

extern PACKAGE AnsiString __fastcall SetToString(PPropInfo PropInfo, int Value, bool Brackets = false);

extern PACKAGE int __fastcall StringToSet(PPropInfo PropInfo, const AnsiString Value);

存取對象型态屬性:

extern PACKAGE System::TObject* __fastcall GetObjectProp(System::TObject* Instance, const AnsiString PropName, TMetaClass* MinClass = 0x0);

extern PACKAGE void __fastcall SetObjectProp(System::TObject* Instance, const AnsiString PropName, System::TObject* Value);

extern PACKAGE TMetaClass* __fastcall GetObjectPropClass(System::TObject* Instance, const AnsiString PropName);

extern PACKAGE System::TObject* __fastcall GetObjectProp(System::TObject* Instance, PPropInfo PropInfo, TMetaClass* MinClass = 0x0);

extern PACKAGE void __fastcall SetObjectProp(System::TObject* Instance, PPropInfo PropInfo, System::TObject* Value, bool ValidateClass = true);

extern PACKAGE TMetaClass* __fastcall GetObjectPropClass(System::TObject* Instance, PPropInfo PropInfo);

extern PACKAGE TMetaClass* __fastcall GetObjectPropClass(PPropInfo PropInfo);

存取AnsiString型态屬性:

extern PACKAGE AnsiString __fastcall GetStrProp(System::TObject* Instance, const AnsiString PropName);

extern PACKAGE void __fastcall SetStrProp(System::TObject* Instance, const AnsiString PropName, const AnsiString Value);

extern PACKAGE AnsiString __fastcall GetStrProp(System::TObject* Instance, PPropInfo PropInfo);

extern PACKAGE void __fastcall SetStrProp(System::TObject* Instance, PPropInfo PropInfo, const AnsiString Value);

存取WideString型态屬性:

extern PACKAGE WideString __fastcall GetWideStrProp(System::TObject* Instance, const AnsiString PropName);

extern PACKAGE void __fastcall SetWideStrProp(System::TObject* Instance, const AnsiString PropName, const WideString Value);

extern PACKAGE WideString __fastcall GetWideStrProp(System::TObject* Instance, PPropInfo PropInfo);

extern PACKAGE void __fastcall SetWideStrProp(System::TObject* Instance, PPropInfo PropInfo, const WideString Value);

存取Variant型态屬性:

extern PACKAGE Variant __fastcall GetVariantProp(System::TObject* Instance, const AnsiString PropName);

extern PACKAGE void __fastcall SetVariantProp(System::TObject* Instance, const AnsiString PropName, const Variant &Value);

extern PACKAGE Variant __fastcall GetVariantProp(System::TObject* Instance, PPropInfo PropInfo);

extern PACKAGE void __fastcall SetVariantProp(System::TObject* Instance, PPropInfo PropInfo, const Variant &Value);

存取Method型态屬性:

extern PACKAGE System::TMethod __fastcall GetMethodProp(System::TObject* Instance, const AnsiString PropName);

extern PACKAGE void __fastcall SetMethodProp(System::TObject* Instance, const AnsiString PropName, const System::TMethod &Value);

extern PACKAGE System::TMethod __fastcall GetMethodProp(System::TObject* Instance, PPropInfo PropInfo);

extern PACKAGE void __fastcall SetMethodProp(System::TObject* Instance, PPropInfo PropInfo, const System::TMethod &Value);

存取Int64型态屬性:

extern PACKAGE __int64 __fastcall GetInt64Prop(System::TObject* Instance, const AnsiString PropName);

extern PACKAGE void __fastcall SetInt64Prop(System::TObject* Instance, const AnsiString PropName, const __int64 Value);

extern PACKAGE __int64 __fastcall GetInt64Prop(System::TObject* Instance, PPropInfo PropInfo);

extern PACKAGE void __fastcall SetInt64Prop(System::TObject* Instance, PPropInfo PropInfo, const __int64 Value);

存取Interface型态屬性:

extern PACKAGE System::_di_IInterface __fastcall GetInterfaceProp(System::TObject* Instance, const AnsiString PropName);

extern PACKAGE void __fastcall SetInterfaceProp(System::TObject* Instance, const AnsiString PropName, const System::_di_IInterface Value);

extern PACKAGE System::_di_IInterface __fastcall GetInterfaceProp(System::TObject* Instance, PPropInfo PropInfo);

extern PACKAGE void __fastcall SetInterfaceProp(System::TObject* Instance, PPropInfo PropInfo, const System::_di_IInterface Value);

    理論上,隻要有 SetPropValue 與 GetPropValue 這兩組函式就夠了。可是,除非您很熟悉 TTypeData 的細節,否則建議您還是使用上述的這些與個别型态相關的函式吧。況且,Borland并未把上面的技術正式公布出來,其中的一個理由就是這些内部結構還有可能會修改。是以,還是别自己亂動的好。另外一件事情就是,上面的函式未必所有C++ Builder的版本都有。建議您還是先看看自己的typinfo.hpp再說吧。

繼續閱讀