wx利用两个宏实现了几乎所有以wx开头的窗口类的反射机制:
DECLARE_DYNAMIC_CLASS
IMPLEMENT_DYNAMIC_CLASS
当一个类想借助于wx实现的dynamic_class的机制,必须得继承于wxObject或者是它的子类。有了这个前提条件之后,在你的类中,你只需要这样操作:
1. 在类的声明中,写下:
DECLARE_DYNAMIC_CLASS($your_class_name);
2. 在类的实现文件中,写下:
IMPLEMENT_DYNAMIC_CLASS($your_class_name, $base_class_from_wxObject);
那么这2个宏到底帮我们做了些什么事情呢,我们来展开那2个宏来看看:
首先是
DECLARE_DYNAMIC_CLASS($your_class_name)
#define DECLARE_ABSTRACT_CLASS (name) \
public: \
static wxClassInfo ms_classInfo; \
virtual wxClassInfo *GetClassInfo() const;
#define DECLARE_DYNAMIC_CLASS (name) \
DECLARE_ABSTRACT_CLASS(name ) \
static wxObject * wxCreateObject();
如果你的类不是抽象类,请用
DECLARE_DYNAMIC_CLASS,否则就用
DECLARE_ABSTRACT_CLASS。区别在于抽象类是无法实例化的,也就没办法提供对象构造器。我们具体来看下
DECLARE_ABSTRACT_CLASS这个宏。
这个宏主要是帮助提供了一个类wxClassInfo的静态变量,用来存储这个类的信息,同时也提供了访问给外界这个静态变量的接口。
所以总体来说,DECLEAR_*宏是在我们类中添加了额外的用来存储类相关信息的一个静态变量。有了这个静态变量,外界就可以通过Get接口来获取它的相关信息。
下面来看看
IMPLEMENT_DYNAMIC_CLASS宏。
#define wxIMPLEMENT_CLASS_COMMON (name, basename, baseclsinfo2, func ) \
wxClassInfo name ::ms_classInfo( wxT(#name ), \
& basename::ms_classInfo , \
baseclsinfo2, \
( int) sizeof (name), \
( wxObjectConstructorFn) func ); \
\
wxClassInfo *name ::GetClassInfo() const \
{ return &name ::ms_classInfo; }
#define wxIMPLEMENT_CLASS_COMMON1 (name, basename, func) \
wxIMPLEMENT_CLASS_COMMON(name , basename, NULL, func)
#define IMPLEMENT_DYNAMIC_CLASS (name, basename) \
wxIMPLEMENT_CLASS_COMMON1(name , basename, name::wxCreateObject ) \
wxObject* name ::wxCreateObject() \
{ return new name; }
wx中最多只能让一个dynamic继承于2个wxObject子类,应该是虚继承。所以
wxIMPLEMENT_CLASS_COMMON只提供了2个basename接口。
从展开的宏来看,它主要做的事情就是初始化我们类的静态变量(ms_classInfo),初始化时,传入的动态对象构造器就是
wxCreateObject(简单的调用new操作符)。
所以下面我们来看下wxClassInfo类。
typedef wxObject *(*wxObjectConstructorFn)( void);
class WXDLLIMPEXP_BASE wxClassInfo
{
public:
wxClassInfo( const wxChar * className,
const wxClassInfo *baseInfo1,
const wxClassInfo *baseInfo2,
int size ,
wxObjectConstructorFn ctor )
: m_className(className )
, m_objectSize(size )
, m_objectConstructor(ctor )
, m_baseInfo1(baseInfo1 )
, m_baseInfo2(baseInfo2 )
, m_next(sm_first )
{
sm_first = this ;
Register();
}
static wxHashTable *sm_classTable;
...
void wxClassInfo ::Register()
{
if ( !sm_classTable )
{
wxHashTable *classTable = new wxHashTable(wxKEY_STRING );
// check for reentrance
if ( sm_classTable )
delete classTable ;
else
sm_classTable = classTable ;
}
sm_classTable->Put (m_className, ( wxObject *)this );
}
这个类的构造函数仅仅是将类和它类名注册到一个hash table中,这个hash table是以类名为字符串作为key.
以上是C++中反射机制的比较典型的实现方式。
wx提供了下面2个宏操作:
#define wxIS_KIND_OF (obj, className) obj->IsKindOf (&className:: ms_classInfo)
// Just seems a bit nicer-looking (pretend it's not a macro)
#define wxIsKindOf (obj, className) obj->IsKindOf (&className:: ms_classInfo)
判断某个类的对象,是否属于某个class,这种属于应该是按照类的继承数来搜索的,满足"IS-A"关系。
有了wx那样实现机制,我们可以通过className可以很容器的查找到关存在它内部的classInfo变量。
IsKindOf函数定义在wxObject内部,要知道wxObject也是添加了DECLEAR*宏的:
DECLARE_ABSTRACT_CLASS
(
wxObject
)
所以自然也有wxClassInfo信息。这个IsKindOf转调用wxClassInfo::IsKindOf。
bool wxObject ::IsKindOf( wxClassInfo *info ) const
{
wxClassInfo *thisInfo = GetClassInfo();
return (thisInfo ) ? thisInfo-> IsKindOf(info ) : false ;
}
bool wxClassInfo::IsKindOf(const wxClassInfo *info ) const
{
return info != 0 &&
( info == this ||
( m_baseInfo1 && m_baseInfo1 ->IsKindOf( info) ) ||
( m_baseInfo2 && m_baseInfo2 ->IsKindOf( info) ) );
}
所以它做的事情很简单,就是判断它们的wxClassInfo是否是同一个,或者如果该请求类有基类的话,基类是否那个条件。