《深入淺出MFC》系列之動態創建


/*********************************************************************************************************************
*   發布日期:2017-11-13 16:23:44
*   進度:
*   作者:LuoTian
*   備注:動態創建
*********************************************************************************************************************/

這一篇承接上一篇的運行時類型識別,當各個類像鏈表一樣串接之后,做各種功能就比較簡單。

動態創建的思路:

動態創建就是指輸入一個類名就能創建一個對象,比如在控制台中輸入Base,就能創建Base類的對象。

假設有三個類Base,B,C,繼承關系為Base<-B<-C,其中Base為根類。根據上一篇所寫,將這三個類通過CRuntimeClass進行串接。因為動態創建需要這個,原因容易理解,假如你輸入一個Base,程序則必須根據輸入的這個字符串在鏈接的類中查找是否存在Base這個類,於是就需要遍歷,從C開始一直查找到Base。

為了實現這些功能,除了在CRuntimeClass里面再添加一些信息之外,還在能動態創建的類中添加一個靜態函數CreateObject( );

流程如下:

假定輸入Base,程序根據pFirst從尾端開始遍歷各個類,查找是否有類名=Base的類,如果不存在則程序返回。如果存在,再看它的一個字段m_pfnCreateObject是否為空,而這個m_pfnCreateObject是一個函數指針,所指向的就是在能動態創建的類中添加的靜態函數CreateObject(),假如一個類不能動態創建,那么肯定沒有這個CreateObject函數,則在初始化CRuntimeClass的時候,m_pfnCreateObject也就為NULL了,如果能動態創建,m_pfnCreateObject就指向了CreateObject( ),然后通過m_pfnCreateObject指針執行函數調用。

思路總結:

一、能動態創建的類中有CreateObject()函數。
二、能動態創建的類的CRuntimeClass結構中的m_pfnCreateObject字段初賦值為CreateObjec,如果為NULL,則不具備動態創建的能力。

//實現比較簡單,直接new一個對象返回;
static Base * PASCAL CreateObject(){return new B;}

示例代碼如下:

#include <iostream>
using namespace std;
#define PASCAL _stdcall
class Base;

/***************核心的CRuntimeClass結構********************/
struct CRuntimeClass
{
    char * name;    //類名
    int ClassSize;    //類大小;
    Base *(PASCAL * m_pfnCreateObject)();
    CRuntimeClass *pBase;//基類的CRuntimeClass地址

    Base * CreateObject();
    static CRuntimeClass * PASCAL Load();
    static CRuntimeClass *pFirst;
    CRuntimeClass *pNext;
};
CRuntimeClass * CRuntimeClass::pFirst=NULL;//pFirst初始化為空;

CRuntimeClass* PASCAL CRuntimeClass::Load()
{
    char szClassName[64];
    CRuntimeClass* pClass;
    cout << "輸入需要動態創建的類名:";
    cin >> szClassName;

    //在各個類的CRuntimeClass結構中查找是否存在輸入的類名
    for (pClass = pFirst; pClass != NULL; pClass = pClass->pNext)
    {
        if (strcmp(szClassName, pClass->name) == 0)
            return pClass;
    }
    cout<<"沒有找到該類名,程序退出!!"<<endl;
    return NULL;
}
Base * CRuntimeClass::CreateObject()
{

    if (m_pfnCreateObject == NULL)
    {
        cout<<"不能動態創建!!"<<endl;
        return NULL;
    }
    else
    {
        Base * pObject =(*m_pfnCreateObject)();    
        return pObject;
    }
}
//****************結束*****************************************/

struct AFX_CLASSINIT
{
    AFX_CLASSINIT(CRuntimeClass *pNewClass)
    {
        pNewClass->pNext=CRuntimeClass::pFirst;
        CRuntimeClass::pFirst=pNewClass;
    }
};

class Base //根基類;
{
public:
    static CRuntimeClass classBase;
    virtual CRuntimeClass * GetRuntimeClass()const
    {
        return &Base::classBase;
    }
    virtual void SayHello()
    {
        cout<<"基類Base的SayHello"<<endl;
    }
};

class B:public Base //B類
{
public:
    static CRuntimeClass classB;
    static Base * PASCAL CreateObject(){return new B;}
    virtual CRuntimeClass * GetRuntimeClass()const{
        return &B::classB;
    }
    virtual void SayHello(){ cout<<"類B的SayHello,動態創建對象成功!!"<<endl;}
};

class C:public B //C類
{
public:
    static CRuntimeClass classC;
    virtual CRuntimeClass * GetRuntimeClass()const{
        return &C::classC;
    }
};

//***********************實現部分*************************//

struct CRuntimeClass Base::classBase={"Base",sizeof(Base),NULL,NULL};
static AFX_CLASSINIT _init_A(&Base::classBase);//

struct CRuntimeClass B::classB={"B",sizeof(B),B::CreateObject,&Base::classBase,};
static AFX_CLASSINIT _init_B(&B::classB);//


struct CRuntimeClass C::classC={"C",sizeof(C),NULL,&B::classB,};
static AFX_CLASSINIT _init_C(&C::classC);//


int main(int argc,char *argv[])
{
    CRuntimeClass * pClassRef;
    Base *pOb;
    cout<<"共有三個類Base,B,C,其中B類具有動態創建能力... ."<<endl;
    while(true)
    {
        if((pClassRef=CRuntimeClass::Load())==NULL)
            break;
        pOb=pClassRef->CreateObject();
        if(pOb!=NULL)
            pOb->SayHello();
    }
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM