http://blog.csdn.net/oowgsoo/article/details/1529411
多态的底层实现机制只有两种,一种是按照名称查表,一种是按照位置查表,两种方式各有利弊,c++的虚函数机制采用了按照位置查表.导致的问题是:子类很多重载的基类实现的时候开销太大.像界面编程这样子类众多的的情况,c++的虚函数机制不适合.于是各家库的编写者采取自家的方法实现按照名称查表的多态实现机制.
例如MFC:消息映射机制,Qt:元对象表机制.
在Qt中,元对象表机制最大的作用就是支持信号槽机制.当然,在此基础上可以扩展出更多的功能.因为元数据是我们可以直接访问到的,不再象虚函数机制那样被编译器隐藏了.
任何从QObject派生的类都包含了自己的元数据模型,一般通过宏Q_OBJECT定义的
在Qt5.3.2中
#define Q_OBJECT\
public: \
Q_OBJECT_CHECK \
static const QMetaObject staticMetaObject;\
virtual const QMetaObject *metaObject()const; \
virtual void *qt_metacast(const char *); \
QT_TR_FUNCTIONS\
virtual int qt_metacall(QMetaObject::Call,int, void **); \
private: \
Q_DECL_HIDDEN_STATIC_METACALL static voidqt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
struct QPrivateSignal {};
QMetaObject类型的静态成员变量,就是元数据的数据结构。
在struct QMetaObject中有一个嵌套类封装了所有的数据
structQ_CORE_EXPORT QMetaObject
{ …
…
…
struct { //private data
const QMetaObject *superdata;
const QByteArrayData *stringdata;
const uint *data;
typedef void(*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **);
StaticMetacallFunction static_metacall;
const QMetaObject * const*relatedMetaObjects;
void *extradata; //reserved for futureuse
} d;
};
const QMetaObject *superdata;//这是元数据代表的类的基类的元数据
const QByteArrayData *stringdata;//这是元数据的签名标记
const uint *data;// 这是元数据的索引数组指针
void *extradata;//这是扩展的元数据表的指针,一般是不用的
在#define Q_OBJECT \下的三个虚函数metaObject()、qt_metacast(constchar *)、qt_metacall(QMetaObject::Call, int, void **)是在moc文件中定义的
metaObject()的作用是得到元数据表的指针
qt_metacast(constchar *)的作用是根据签名得到相关结构的指针,返回值为void*指针
qt_metacall(QMetaObject::Call,int, void **)的作用是查表然后调用相关的函数
宏QT_TR_FUNCTIONS 是和翻译相关的
深入浅出MFC第一篇第三章-消息映射一节
MFC:消息映射机制
MFC在类中实现消息映射机制需要4个宏,一个用于声明,三个用于定义
DECLARE_MESSAGE_MAP();//声明消息映射表的宏
//定义消息映射表的实现的3个宏
BEGIN_MESSAGE_MAP(theClass,baseClass)
ON_COMMAND(id,memberFxn)
defineEND_MESSAGE_MAP()
我们看到,实现的3个宏中,需要涉及到该类的基类,而Qt在使用时,只需继承QOBject和添上一个宏Q_OBJECT。但MFC里的消息映射机制理解起来比Qt简单。Qt的元对象表使用起来简单。
下面构建出整个消息映射表
首先,是三个数据结构
struct AFX_MSGMAP //消息映射表
{
AFX_MSGMAP*pBaseMessageMap; //基类的消息映射表指针
AFX_MSGMAP_ENTRY*lpEntries; //
};
struct AFX_MSGMAP_ENTRY // MFC 4.0 format//消息映射实体
{
UINTnMessage; // windows message //windows消息
UINT nCode; // control code or WM_NOTIFY code
UINT nID; // control ID (or 0 for windows messages)
UINTnLastID; // used for entriesspecifying a range of control id's
UINT nSig; // signature type (action) or pointer tomessage #
AFX_PMSGpfn; // routine to call (or special value)
};
typedef void(CCmdTarget::*AFX_PMSG)(void);//函数指针,要调用的函数
然后是宏DECLARE_MESSAGE_MAP();//声明消息映射表的宏
#defineDECLARE_MESSAGE_MAP()\
staticAFX_MSGMAP_ENTRY _messageEntries[]; \
staticAFX_MSGMAP messageMap; \
virtual AFX_MSGMAP* GetMessageMap() const;
声明一个AFX_MSGMAP结构的messageMap和一组消息实体
AFX_MSGMAP_ENTRY_messageEntries[]以及一个获取消息表的虚函数GetMessageMap()。
最后是三个定义消息映射表的宏BEGIN_MESSAGE_MAP(theClass,baseClass)、
ON_COMMAND(id,memberFxn)、define END_MESSAGE_MAP()
#defineBEGIN_MESSAGE_MAP(theClass, baseClass) \
AFX_MSGMAP*theClass::GetMessageMap()const \
{ return &theClass::messageMap; } \ //GetMessageMap()的定义
AFX_MSGMAPtheClass::messageMap= \
{&(baseClass::messageMap),\
(AFX_MSGMAP_ENTRY*)&(theClass::_messageEntries)}; \ //消息映射表的定义
AFX_MSGMAP_ENTRYtheClass::_messageEntries[]= \ //消息映射实体定义数组的前半部
#defineON_COMMAND(id, memberFxn) \
{WM_COMMAND, 0,(WORD)id, (WORD)id, AfxSig_vv, (AFX_PMSG)memberFxn },
// 数组中放入一个特定的消息映射实体,消息实体只获取id和调用函数memberFxn参数,其他取默认值
#defineEND_MESSAGE_MAP() \
{0, 0, 0, 0,AfxSig_end, (AFX_PMSG)0 } \
}; //消息映射实体定义数组的后半部