MFC运行时动态类实现

  • MD DocUmEnT: 4/2/2016 12:28:57 AM by Jimbowhy

技术背景

MFC是微软为数不多,公开源代码发布的一个软件框架,深入的技术分析可以参考侯俊杰先生的《深入浅出MFC》,资料确实非常赞,作者真可谓知无言,言无不尽。虽然现在有许多关于MFC过时与否的讨论,个人觉得没有必要参与其中,所有事物其实都会有过时的那天,人也是如此。对于没有掌握的一种技术,那就是新的,并非过时,过时只是对于前面那批会MFC却又不用MFC做事的人来说的。我并没有完全掌握MFC,但我也没有必要完全去掌握MFC,只是喜欢MFC,喜欢学习其中的实现技术。MFC并不一定能减轻程序开发的负担,相反它可能会很大程序上增加程序人员的工作量,如果不适当地应用这种技术。

运行时类型信息 RTTI,Run-Time Type Information 和动态类型 Dynmic Class 作为MFC六大核心机制其中之二,联系非常紧密,就像消息映射 Message Mapping 和命令传递 Command Routing一样结合紧密。其余两项核心技术,MFC初始化与持久化 Persistence 则相对独立。而消息映射机制和动态类型则是我认为最有趣的两大技术,C++标准也有RTTI的实现,但MFC比它更早。

实现代码

要掌握动态类型光靠文字描述效果不怎样,其实写下代码最有说服力,从代码的角度理解动态类型的工作原理是十分贴切的。实现完整的动态类型可以粗分为四个步骤,首先是创建动态类型基础,它可以记录系统所有动态类型信息,其作用相当于数据库,代码实现上它就是一张一维链表,通过表头一直接驳到最原始的基类。有了基础类型,接下来就需要一个特殊的结构体用来记录这些动态类的链表信息。第三步就是最重要的一步,通过宏将前面两部分内容组织到具体的类定义及实现过程中。最后,在定义类时,引用这些宏定义来完成动态类型的定义,以下是具体代码实现:

基础类定义

/*****************************************************************************\

    Runtime Type Information demo by Jimbowhy 2016/4/1 23:50
    Compiler: Visual C++ 6, TDM-GCC 3.7.1

    This programme is a demonstration of how MFC implementates RuntimeClass

\*****************************************************************************/


#include <iostream>
#include <cstring>

using namespace std;

/*
 * --------------=========== Step I: Runtime Classs ===========---------------
 */
class CRuntimeClass {
    public:
        char * name; // keep order for the first 4 members
        int    size;
        void * (* constructor)();
        CRuntimeClass* pBase;
        CRuntimeClass* pNext;
        static CRuntimeClass* theFirst;
        static void * CreateObject(char *);
        bool isKindOf(const CRuntimeClass*) const;
};

CRuntimeClass *CRuntimeClass::theFirst = NULL;

bool CRuntimeClass::isKindOf(const CRuntimeClass *c) const {
    const CRuntimeClass *p = this;
    while(p){
        if( c==p ) return true;
        p = p->pBase;
    }
    return false;
}

void *CRuntimeClass::CreateObject(char * classname){
    CRuntimeClass *c = CRuntimeClass::theFirst;
    while(c){
        CRuntimeClass &cr = *c;
        if( strcmp(classname, cr.name) == 0 ) break;
        c = cr.pNext;
    }
    CRuntimeClass &cr = *c;
    if( c==NULL) throw "Not a valid dynamic class specified!";
    if( cr.constructor==NULL ) return NULL;
    return cr.constructor();
}

辅助结构

/*
 * --------------=========== Step II: Runtime Auxiliary ===========---------------
 */
struct AFX_CLASSINIT {
    AFX_CLASSINIT(CRuntimeClass *);
};

AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass* pNew){
    pNew->pNext = CRuntimeClass::theFirst;
    CRuntimeClass::theFirst = pNew;
}

宏结构

/*
 * --------------============ Step IV: Macro Auxiliary ===========---------------
 */
#define DECLARE_DYNAMIC \
        static CRuntimeClass Class; \
        static AFX_CLASSINIT ClassInit;

#define IMPLEMENT_DYNAMIC(ClassName, Base) \
        CRuntimeClass ClassName::Class = { #ClassName, sizeof(ClassName), NULL, &Base::Class };\
        AFX_CLASSINIT ClassName::ClassInit(&ClassName::Class); 

#define DECLARE_DYNCREATE \
        DECLARE_DYNAMIC \
        static void * CreateObject();

#define IMPLEMENT_DYNCREATE(ClassName, Base) \
        void *ClassName::CreateObject(){ return new ClassName(); } \
        CRuntimeClass ClassName::Class = { #ClassName, sizeof(ClassName), ClassName::CreateObject, &Base::Class };\
        AFX_CLASSINIT ClassName::ClassInit(&ClassName::Class);  

应用动态类

/*
 * --------------=========== Step V: Use Runtime Class ===========---------------
 */
class Shape {
    public:
        Shape() {
            cout << "Raw shape" << endl;
        }
        DECLARE_DYNCREATE
};
IMPLEMENT_DYNCREATE(Shape, Shape)

class Trangle: public Shape {
    public:
        Trangle (){
            cout << "Trangle" << endl;
        }
        DECLARE_DYNCREATE
};
IMPLEMENT_DYNCREATE(Trangle, Shape)

class Ellipse: public Shape {
    public:
        Ellipse(){
            cout << "Ellipse" << endl;
        }
        DECLARE_DYNAMIC
};
IMPLEMENT_DYNAMIC(Ellipse, Shape)

测试程序入口

/*
 * ---------------============== Programme Entry ==============----------------
 */
void main(){
    char classname[256];
    cout << "Try RuntimeClass, dynamicaly create, Shape, Trangle, Ellipse, and more...\n";
    cout << "Type what class you want now:";
    while(1)
    try{
        cin >> classname;
        void * o = CRuntimeClass::CreateObject(classname);
        if( o==NULL ){
            cout << "Not a dynamicaly create class specified!" << endl;
            return;
        }
    }catch(char* m){
        cout << m << endl;
    }
}

以上就是一个完整的动态类实现过程,至于运行时类型信息机制其实也已经是五脏俱全了,只要添加typeid,isKindOf之类的运算符就可以很好地解决运行时类型问题。

全文完。

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐