BCB中的RTTI机制
void __fastcall TForm1::Button2Click(TObject *Sender)
{
if (GetPropInfo(Button2, "Caption"))
Caption = GetPropValue(Button2, "Caption");
}
{
if (GetPropInfo(Button2, "Caption"))
Caption = GetPropValue(Button2, "Caption");
}
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 {
public:
void ShowMe();
};
viod Show(CShape *someShape) {
someShape->ShowMe();
}
int main(void) {
CRectangle myRect ;
Show(&myRect);
CNotShape notShape ;
Show(¬Shape); // Error!!
}
…
public:
virtual void ShowMe() = 0; // Virtual function
} ;
class CRectangle {
public:
void ShowMe();
};
viod Show(CShape *someShape) {
someShape->ShowMe();
}
int main(void) {
CRectangle myRect ;
Show(&myRect);
CNotShape notShape ;
Show(¬Shape); // 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.
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;
using namespace std;
透过typeid()我们可以取得特定的型态的信息。例如,想要比较两个变量是否为相同型态。您可以写成下面的形式:
template <class T, class D>
bool isSameType(T var1, D var2)
{
return (typeid(var1) == typeid(var2));
}
bool isSameType(T var1, D var2)
{
return (typeid(var1) == typeid(var2));
}
这个函式可用来比较两个变量的型态是否相等。
若您想取得型态的名称。您可使用typeid()所传回来的型态的name()函式。例如:
int a;
ShowMessage(typeid(int).name());
ShowMessage(typeid(a).name());
ShowMessage(typeid(int).name());
ShowMessage(typeid(a).name());
若您想确认两者之间有无继承关系,可使用typeid()所传回来的型态中的before()函式。before()函式中有一个参数也是一个由 typeid()所传回的型态信息。以前面的例子来说,若您想切确知道CShape是否在CRectangle之前(也就是是否CRectangle为 CShape的祖先),可用下面的程序来判断:
if( typeid(CShape).before(typeid(CRectangle)) )
{
return true ;
}
{
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.
int *p = &i ; // Compile error! Cannot cast from const to violate.
但是您可能非常确定自己想要做什么,所以您可使用const_cast明确的告诉compiler做您要求的动作。
const i = 0;
int *p = const_cast<int *>(&i) ; // OK.
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);
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);
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()); }
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));
…
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;
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 =
System::Set<TTypeKind, tkUnknown, tkDynArray> () );
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);
Instance, const AnsiString PropName, TTypeKinds AKinds =
System::Set<TTypeKind, tkUnknown, tkDynArray> () );
extern PACKAGE PPropInfo __fastcall GetPropInfo(TMetaClass* AClass,
const AnsiString PropName, TTypeKinds AKinds =
System::Set<TTypeKind, tkUnknown, tkDynArray> () );
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);
GetPropInfos(Form1->ClassInfo(),(PPropList)&List);
如果您想取得符合某些特定型态的属性,(可排序)
TPropList List;
int Count = GetPropList((PTypeInfo)(Form1->ClassInfo()), tkAny, (PPropList)&List);
int Count = GetPropList((PTypeInfo)(Form1->ClassInfo()), tkAny, (PPropList)&List);
tkAny 全部属性
tkMethods 事件属性
tkProperties 属性
不过这里有个问题,如果您去看一下TPropList的定义,会发现他其实是一个非常大的指针数组。这样内存是蛮浪费的,所以建议您可以换种方式:
int count = GetPropList((PTypeInfo)(Form1->ClassInfo()), tkAny, NULL);
PPropList list = new PPropInfo[count];
try {
GetPropList((PTypeInfo)ClassInfo(), tkAny, list);
}
__finally {
delete [ ] list ;
}
try {
GetPropList((PTypeInfo)ClassInfo(), tkAny, list);
}
__finally {
delete [ ] list ;
}
也可以这样获取
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TPropList List;
PTypeInfo TypeInfo = (PTypeInfo)ClassInfo(); //取得Form1的所有属性
int Count = GetTypeData(TypeInfo)->PropCount;
GetPropInfos(TypeInfo, List);
for(int n=0; n<Count; n++) {
ListBox1->Items->Add(List[n]->Name);
}
}
{
TPropList List;
PTypeInfo TypeInfo = (PTypeInfo)ClassInfo(); //取得Form1的所有属性
int Count = GetTypeData(TypeInfo)->PropCount;
GetPropInfos(TypeInfo, List);
for(int n=0; n<Count; n++) {
ListBox1->Items->Add(List[n]->Name);
}
}
其中,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) )
<< 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 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 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 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 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 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 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 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);
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);
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);
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);
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);
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);
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);
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再说吧。
参考数据:
- 『Run-Time Type Information In C++Builder 5 - What Can It Do For You?』by Brain Long, www.blong.com.