• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            唐吉訶德

              C++博客 :: 首頁 :: 聯系 :: 聚合  :: 管理
              5 Posts :: 75 Stories :: 3 Comments :: 0 Trackbacks

            常用鏈接

            留言簿(2)

            我參與的團隊

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            今天在網上突然發現了下面幾個關于c代碼中的宏定義的說明,回想下,好像在系統的代碼中也見過這些零散的定義,但沒有注意,看到別人總結了下,發現果然很有用,雖然不知有的道可用與否,但也不失為一種手段,所以就先把它摘抄下來,增加一點見識:

            1,防止一個頭文件被重復包含
            #ifndef BODYDEF_H
            #define BODYDEF_H
              //頭文件內容
            #endif
            2,得到指定地址上的一個字節或字
            #define  MEM_B( x )  ( *( (byte *) (x) ) )
            #define  MEM_W( x )  ( *( (word *) (x) ) )
            3,得到一個field在結構體(struct)中的偏移量
            #define FPOS( type, field ) ( (dword) &(( type *) 0)-> field )
            4,得到一個結構體中field所占用的字節數
            #define FSIZ( type, field ) sizeof( ((type *) 0)->field )
            5,得到一個變量的地址(word寬度)
            #define  B_PTR( var )  ( (byte *) (void *) &(var) )
            #define  W_PTR( var )  ( (word *) (void *) &(var) )
            6,將一個字母轉換為大寫
            #define  UPCASE( c ) ( ((c) >= ''a'' && (c) <= ''z'') ? ((c) - 0x20) : (c) )
            7,判斷字符是不是10進值的數字
            #define  DECCHK( c ) ((c) >= ''0'' && (c) <= ''9'')
            8,判斷字符是不是16進值的數字
            #define  HEXCHK( c ) ( ((c) >= ''0'' && (c) <= ''9'') ||((c) >= ''A'' && (c) <= ''F'') ||((c) >= ''a'' && (c) <= ''f'') )
            9,防止溢出的一個方法
            #define  INC_SAT( val )  (val = ((val)+1 > (val)) ? (val)+1 : (val))
            10,返回數組元素的個數
            #define  ARR_SIZE( a )  ( sizeof( (a) ) / sizeof( (a[0]) ) )
            11,使用一些宏跟蹤調試
            ANSI標準說明了五個預定義的宏名。它們是:
            _LINE_ (兩個下劃線),對應%d
            _FILE_     對應%s
            _DATE_   對應%s
            _TIME_    對應%s
            _STDC_

             
            宏中"#"和"##"的用法
            我們使用#把宏參數變為一個字符串,用##把兩個宏參數貼合在一起.
            #define STR(s)     #s
            #define CONS(a,b)  int(a##e##b)
            Printf(STR(vck));           // 輸出字符串"vck"
            printf("%d\n", CONS(2,3));  // 2e3 輸出:2000

            當宏參數是另一個宏的時候
            需要注意的是凡宏定義里有用"#"或"##"的地方宏參數是不會再展開.
            #define A          (2)
            #define STR(s)     #s
            #define CONS(a,b)  int(a##e##b)
            printf("%s\n", CONS(A, A));               // compile error 
            這一行則是:
            printf("%s\n", int(AeA));
            INT_MAX和A都不會再被展開, 然而解決這個問題的方法很簡單. 加多一層中間轉換宏.
            加這層宏的用意是把所有宏的參數在這層里全部展開, 那么在轉換宏里的那一個宏(_STR)就能得到正確的宏參數
            #define STR(s)      _STR(s)          // 轉換宏
            #define CONS(a,b)   _CONS(a,b)       // 轉換宏
            printf("int max: %s\n", STR(INT_MAX));          // INT_MAX,int型的最大值,為一個變量 #include<climits>
            輸出為: int max: 0x7fffffff
            STR(INT_MAX) -->  _STR(0x7fffffff) 然后再轉換成字符串;

            printf("%d\n", CONS(A, A));
            輸出為:200
            CONS(A, A)  -->  _CONS((2), (2))  --> int((2)e(2))

            "#"和"##"的一些應用特例
            1、合并匿名變量名
            #define  ___ANONYMOUS1(type, var, line)  type  var##line
            #define  __ANONYMOUS0(type, line)  ___ANONYMOUS1(type, _anonymous, line)
            #define  ANONYMOUS(type)  __ANONYMOUS0(type, __LINE__)
            例:ANONYMOUS(static int);  即: static int _anonymous70;  70表示該行行號;
            第一層:ANONYMOUS(static int);  -->  __ANONYMOUS0(static int, __LINE__);
            第二層:                        -->  ___ANONYMOUS1(static int, _anonymous, 70);
            第三層:                        -->  static int  _anonymous70;
            即每次只能解開當前層的宏,所以__LINE__在第二層才能被解開;

            2、填充結構
            #define  FILL(a)   {a, #a}

            enum IDD{OPEN, CLOSE};
            typedef struct MSG{
              IDD id;
              const char * msg;
            }MSG;

            MSG _msg[] = {FILL(OPEN), FILL(CLOSE)};
            相當于:
            MSG _msg[] = {{OPEN, "OPEN"},
                          {CLOSE, "CLOSE"}};

            3、記錄文件名
            #define  _GET_FILE_NAME(f)   #f
            #define  GET_FILE_NAME(f)    _GET_FILE_NAME(f)
            static char  FILE_NAME[] = GET_FILE_NAME(__FILE__);

            4、得到一個數值類型所對應的字符串緩沖大小
            #define  _TYPE_BUF_SIZE(type)  sizeof #type
            #define  TYPE_BUF_SIZE(type)   _TYPE_BUF_SIZE(type)
            char  buf[TYPE_BUF_SIZE(INT_MAX)];
                 -->  char  buf[_TYPE_BUF_SIZE(0x7fffffff)];
                 -->  char  buf[sizeof "0x7fffffff"];
            這里相當于:
            char  buf[11]; 

            C++提供的編譯預處理功能主要有以下三種:
              (一) 宏定義
              (二) 文件包含
              (三) 條件編譯

            在C++中,我們一般用const定義符號常量。很顯然,用const定義常量比用define定義常量更好。
              在使用宏定義時應注意的是:
              (a) 在書寫#define 命令時,注意<宏名>和<字符串>之間用空格分開,而不是用等號連接。
              (b) 使用#define定義的標識符不是變量,它只用作宏替換,因此不占有內存。
              (c) 習慣上用大寫字母表示<宏名>,這只是一種習慣的約定,其目的是為了與變量名區分,因為變量名
                                通常用小寫字母。
              如果某一個標識符被定義為宏名后,在取消該宏定義之前,不允許重新對它進行宏定義。取消宏定義使用如下命令:
              #undef<標識符>
              其中,undef是關鍵字。該命令的功能是取消對<標識符>已有的宏定義。被取消了宏定義的標識符,可以對它重新進行定義。
              宏定義可以嵌套,已被定義的標識符可以用來定義新的標識符。例如:
              #define PI 3.14159265
              #define R 10
              #define AREA (PI*R*R)
            單的宏定義將一個標識符定義為一個字符串,源程序中的該標識符均以指定的字符串來代替。前面已經說過,預處理命令不同于一般C++語句。因此預處理命令后通常不加分號。這并不是說所有的預處理命令后都不能有分號出現。由于宏定義只是用宏名對一個字符串進行簡單的替換,因此如果在宏定義命令后加了分號,將會連同分號一起進行置換。

            帶參數的宏定義
              帶參數的宏定義的一般形式如下:
              #define <宏名>(<參數表>) <宏體>
              其中, <宏名>是一個標識符,<參數表>中的參數可以是一個,也可以是多個,視具體情況而定,當有多個參數的時候,每個參數之間用逗號分隔。<宏體>是被替換用的字符串,宏體中的字符串是由參數表中的各個參數組成的表達式。例如:
              #define SUB(a,b) a-b
            如果在程序中出現如下語句:
              result=SUB(2, 3)
            則被替換為:
              result=2-3;
            如果程序中出現如下語句:
              result= SUB(x+1, y+2);
            則被替換為:
              result=x+1-y+2;
              在這樣的宏替換過程中,其實只是將參數表中的參數代入到宏體的表達式中去,上述例子中,即是將表達式中的a和b分別用2和3代入。
              我們可以發現:帶參的宏定義與函數類似。如果我們把宏定義時出現的參數視為形參,而在程序中引用宏定義時出現的參數視為實參。那么上例中的a和b就是形參,而2和3以及x+1和y+2都為實參。在宏替換時,就是用實參來替換<宏體>中的形參。
            使用帶參數的宏定義時需要注意的是:
              (1)帶參數的宏定義的<宏體>應寫在一行上,如果需要寫在多行上時,在每行結束時,使用續行符 "\"結
                              束,并在該符號后按下回車鍵,最后一行除外。
              (2)在書寫帶參數的宏定義時,<宏名>與左括號之間不能出現空格,否則空格右邊的部分都作為宏體。
                              例如:
                        #define ADD (x,y) x+y
                              將會把"(x,y)x+y"的一個整體作為被定義的字符串。
             (3)定義帶參數的宏時,宏體中與參數名相同的字符串適當地加上圓括號是十分重要的,這樣能夠避免
                              可能產生的錯誤。例如,對于宏定義:
                         #define SQ(x) x*x
                             當程序中出現下列語句:
                        m=SQ(a+b);
                             替換結果為:
                       m=a+b*a+b;
            這可能不是我們期望的結果,如果需要下面的替換結果:
              m=(a+b)*(a+b);
            應將宏定義修改為:
              #define SQ(x) (x)*(x)
              對于帶參的宏定義展開置換的方法是:在程序中如果有帶實參的宏(如"SUB(2,3)"),則按"#define"命令行中指定的字符串從左到右進行置換。如果串中包含宏中的形參(如a、b),則將程序語句中相應的實參(可以是常量、變量或者表達式)代替形參,如果宏定義中的字符串中的字符不是參數字符(如a-b中的-號),則保留。這樣就形成了置換的字符串。 C++提供的編譯預處理功能主要有以下三種:
              (一) 宏定義
              (二) 文件包含
              (三) 條件編譯

            在C++中,我們一般用const定義符號常量。很顯然,用const定義常量比用define定義常量更好。
              在使用宏定義時應注意的是:
              (a) 在書寫#define 命令時,注意<宏名>和<字符串>之間用空格分開,而不是用等號連接。
              (b) 使用#define定義的標識符不是變量,它只用作宏替換,因此不占有內存。
              (c) 習慣上用大寫字母表示<宏名>,這只是一種習慣的約定,其目的是為了與變量名區分,因為變量名
                                通常用小寫字母。
              如果某一個標識符被定義為宏名后,在取消該宏定義之前,不允許重新對它進行宏定義。取消宏定義使用如下命令:
              #undef<標識符>
              其中,undef是關鍵字。該命令的功能是取消對<標識符>已有的宏定義。被取消了宏定義的標識符,可以對它重新進行定義。
              宏定義可以嵌套,已被定義的標識符可以用來定義新的標識符。例如:
              #define PI 3.14159265
              #define R 10
              #define AREA (PI*R*R)
            單的宏定義將一個標識符定義為一個字符串,源程序中的該標識符均以指定的字符串來代替。前面已經說過,預處理命令不同于一般C++語句。因此預處理命令后通常不加分號。這并不是說所有的預處理命令后都不能有分號出現。由于宏定義只是用宏名對一個字符串進行簡單的替換,因此如果在宏定義命令后加了分號,將會連同分號一起進行置換。

            帶參數的宏定義
              帶參數的宏定義的一般形式如下:
              #define <宏名>(<參數表>) <宏體>
              其中, <宏名>是一個標識符,<參數表>中的參數可以是一個,也可以是多個,視具體情況而定,當有多個參數的時候,每個參數之間用逗號分隔。<宏體>是被替換用的字符串,宏體中的字符串是由參數表中的各個參數組成的表達式。例如:
              #define SUB(a,b) a-b
            如果在程序中出現如下語句:
              result=SUB(2, 3)
            則被替換為:
              result=2-3;
            如果程序中出現如下語句:
              result= SUB(x+1, y+2);
            則被替換為:
              result=x+1-y+2;
              在這樣的宏替換過程中,其實只是將參數表中的參數代入到宏體的表達式中去,上述例子中,即是將表達式中的a和b分別用2和3代入。
              我們可以發現:帶參的宏定義與函數類似。如果我們把宏定義時出現的參數視為形參,而在程序中引用宏定義時出現的參數視為實參。那么上例中的a和b就是形參,而2和3以及x+1和y+2都為實參。在宏替換時,就是用實參來替換<宏體>中的形參。
            使用帶參數的宏定義時需要注意的是:
              (1)帶參數的宏定義的<宏體>應寫在一行上,如果需要寫在多行上時,在每行結束時,使用續行符 "\"結
                              束,并在該符號后按下回車鍵,最后一行除外。
              (2)在書寫帶參數的宏定義時,<宏名>與左括號之間不能出現空格,否則空格右邊的部分都作為宏體。
                              例如:
                        #define ADD (x,y) x+y
                              將會把"(x,y)x+y"的一個整體作為被定義的字符串。
             (3)定義帶參數的宏時,宏體中與參數名相同的字符串適當地加上圓括號是十分重要的,這樣能夠避免
                              可能產生的錯誤。例如,對于宏定義:
                         #define SQ(x) x*x
                             當程序中出現下列語句:
                        m=SQ(a+b);
                             替換結果為:
                       m=a+b*a+b;
            這可能不是我們期望的結果,如果需要下面的替換結果:
              m=(a+b)*(a+b);
            應將宏定義修改為:
              #define SQ(x) (x)*(x)
              對于帶參的宏定義展開置換的方法是:在程序中如果有帶實參的宏(如"SUB(2,3)"),則按"#define"命令行中指定的字符串從左到右進行置換。如果串中包含宏中的形參(如a、b),則將程序語句中相應的實參(可以是常量、變量或者表達式)代替形參,如果宏定義中的字符串中的字符不是參數字符(如a-b中的-號),則保留。這樣就形成了置換的字符串。

            解剖MFC自動生成的宏定義

            一、關于DECLARE_MESSAGE_MAP宏定義
            使用MFC向導,在ApplicationType頁面選擇DialogBased,生成一個對話框項目,Dialog類命名為CCapturePacketDlg,在CCapturePacketDlg.cpp中自動產生下列代碼:

            1 BEGIN_MESSAGE_MAP(CCapturePacketDlg, CDialog)
            2     ON_WM_PAINT()
            3 END_MESSAGE_MAP()
            1. 先來分析ON_WM_PAINT(),在頭文件“afxmsg.h”有它的宏定義,如下:
            1 #define  ON_WM_PAINT() \
            2      { WM_PAINT,  0 0 0 , AfxSig_vv, \
            3         (AFX_PMSG)(AFX_PMSGW) \
            4         (static_cast <   void  (AFX_MSG_CALL CWnd:: * )( void >  (  & ThisClass :: OnPaint)) }
            ,
            說明:層次序號x.y.z表示x為根節點也就是上面代碼中的行號,y、z為上一級的定義展開。
            2.1 #define WM_PAINT                        0x000F
            2.2 AfxSig_vv = AfxSig_v_v_v
            2.2.1 enum AfxSig::AfxSig_v_v_v = 19

            3.1 AFX_PMSG:typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void); //為一個函數指針
            3.2 AFX_PMSGW:typedef void (AFX_MSG_CALL CWnd::*AFX_PMSGW)(void);   //為一個函數指針

            將ON_WM_PAINT()完全展開:
            1{
            2        0x000F
            3        0,
            4        0,
            5        0,
            6        19,
            7        //Converts OnPaint to the type of CCmdTarget finally. Derive Class 's pointer -> Base Class's pointer
            8        (AFX_MSG_CALL CCmdTarget::*)((AFX_MSG_CALL CWnd::*)(static_cast< void (AFX_MSG_CALL CWnd::*)(void>(&ThisClass :: OnPaint))
            9    }

               2.   再來分析BEGIN_MESSAGE_MAP(CCapturePacketDlg, CDialog),在“afxwin.h”中有定義:

             1#define BEGIN_MESSAGE_MAP(theClass, baseClass) \
             2    PTM_WARNING_DISABLE \
             3    const AFX_MSGMAP* theClass::GetMessageMap() const \
             4        return GetThisMessageMap(); } \
             5    const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() \
             6    { \
             7        typedef theClass ThisClass;                           \
             8        typedef baseClass TheBaseClass;                       \
             9        static const AFX_MSGMAP_ENTRY _messageEntries[] =  \
            10        {

            2.1 PTM_WARNING_DISABLE:
            #define PTM_WARNING_DISABLE \
             __pragma(warning( push ))  \ //#pragma warning( push [ ,n ] ),Where n represents a warning level (1 through 4).
                                                          //The pragma warning( push ) stores the current warning state for all warnings.
             __pragma(warning( disable : 4867 ))//Do not issue the specified warning message(s).
            //http://msdn2.microsoft.com/en-us/2c8f766e.aspx
            // Allows selective modification of the behavior of compiler warning messages.
            3.1 struct AFX_MSGMAP
             {
              3.1.1 const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
              3.1.2 const AFX_MSGMAP_ENTRY* lpEntries;
             };
            3.1.2 struct AFX_MSGMAP_ENTRY
             {
              UINT nMessage;   // windows message
              UINT nCode;      // control code or WM_NOTIFY code
              UINT nID;        // control ID (or 0 for windows messages)
              UINT nLastID;    // used for entries specifying a range of control id's
              UINT_PTR nSig;       // signature type (action) or pointer to message #
              3.1.2.1 AFX_PMSG pfn;    // routine to call (or special value)
             };
             3.1.2.1 typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);

            5.1 #define PASCAL      __stdcall
            將BEGIN_MESSAGE_MAP(CCapturePacketDlg, CDialog)完全展開:

             1__pragma(warning( push )) __pragma(warning( disable : 4867 ))
             2    const struct AFX_MSGMAP* CCapturePacketDlg::GetMessageMap() const
             3    
             4        return GetThisMessageMap(); 
             5    }

             6    const struct AFX_MSGMAP* __stdcall CCapturePacketDlg::GetThisMessageMap()
             7    {
             8        typedef CCapturePacketDlg ThisClass;                           
             9        typedef CDialog TheBaseClass;        
            10        static const struct AFX_MSGMAP_ENTRY _messageEntries[] = 
            11        {

               3    最后分析END_MESSAGE_MAP(),在“afxwin.h”中有定義:

            1#define END_MESSAGE_MAP() \
            2        {0000, AfxSig_end, (AFX_PMSG)0 } \
            3    }; \
            4        static const AFX_MSGMAP messageMap = \
            5        &TheBaseClass::GetThisMessageMap, &_messageEntries[0] }; \
            6        return &messageMap; \
            7    }                                  \
            8    PTM_WARNING_RESTORE

            2.1 AfxSig_end:enum AfxSig.AfxSig_end = 0
            2.2 AFX_PMSG:typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);//函數指針

            4.1 struct AFX_MSGMAP
             {
              const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
              const AFX_MSGMAP_ENTRY* lpEntries;
             };

            8.1 #define PTM_WARNING_RESTORE \
             __pragma(warning( pop ))
            //pop restores the state of all warnings (including 4705, 4706, and 4707) to what it was at the beginning of the code.

            ·最后將

            1BEGIN_MESSAGE_MAP(CCapturePacketDlg, CDialog)
            2    ON_WM_PAINT()
            3END_MESSAGE_MAP()
            完全展開為:
             1__pragma(warning( push )) __pragma(warning( disable : 4867 ))
             2    const struct AFX_MSGMAP* CCapturePacketDlg::GetMessageMap() const
             3    
             4        return GetThisMessageMap(); 
             5    }

             6    const struct AFX_MSGMAP* __stdcall CCapturePacketDlg::GetThisMessageMap()
             7    {
             8        typedef CCapturePacketDlg ThisClass;                           
             9        typedef CDialog TheBaseClass;        
            10        static const struct AFX_MSGMAP_ENTRY _messageEntries[] = 
            11        {
            12            {
            13                0x000F
            14                0,
            15                0,
            16                0,
            17                19,
            18                //Converts OnPaint to the type of CCmdTarget finally. Derive Class 's pointer -> Base Class's pointer
            19                (AFX_MSG_CALL CCmdTarget::*)((AFX_MSG_CALL CWnd::*)(static_cast< void (AFX_MSG_CALL CWnd::*)(void>(&ThisClass :: OnPaint))
            20            }
            ,
            21            //add others
            22            {
            23                0,
            24                0,
            25                0,
            26                0,
            27                0,
            28                (AFX_PMSG)0
            29            }

            30        }

            31        static const struct AFX_MSGMAP messageMap = 
            32        {
            33            &TheBaseClass::GetThisMessageMap,
            34            &_messageEntries[0]
            35        }
            ;
            36        return &messageMap;
            37    }

            38__pragma(warning( pop ))
            39
            其中GetMessageMap()是在哪里聲明的呢?在CCapturePacketDlg的定義中有一個這樣的宏:DECLARE_MESSAGE_MAP()
            老辦法查看它的定義:
            1#define DECLARE_MESSAGE_MAP() \
            2protected: \
            3    static const AFX_MSGMAP* PASCAL GetThisMessageMap(); \
            4    virtual const AFX_MSGMAP* GetMessageMap() const; \
            注意函數為static,即它們是類的函數。函數中的static變量實際也在類對象未生成之前已經存在。(這種說法不知道是否正確?)
            小結:
            每次用MFC類向導生成一個類時,系統會在類的聲明部分添加兩個方法的聲明:GetThisMessageMap(),GetMessageMap()。在類的實現部分.cpp文件中加上這兩個方法的定義。
            當然這所有的代碼都是由系統生成的,如果我們要定義自己的消息處理函數呢,例如,我們要添加一個按鈕(ID為:IDC_BUTTON1)的單擊處理函數我們可以添加宏ON_NOTIFY(NM_CLICK, IDC_BUTTON1, OnMyClick),OnMyClick為自定義函數,但是他必須與ON_NOTIFY中的函數原型一致。

            二、關于DECLARE_DYNCREATE宏
            使用MFC向導,在ApplicationType頁面選擇SingleDocument,生成一個單文檔項目,Document類命名為CDynamicDoc,在CDynamicDoc.h中自動產生DECLARE_DYNCREATE(CDynamicDoc),CDynamicDoc.cpp中產生IMPLEMENT_DYNCREATE(CDynamicDoc, CDocument)。
            1、展開CDynamicDoc.h中的DECLARE_DYNCREATE(CDynamicDoc):
            1// not serializable, but dynamically constructable
            2    #define DECLARE_DYNCREATE(class_name) \
            3        DECLARE_DYNAMIC(class_name) \
            4        static CObject* PASCAL CreateObject();
            3.1如下定義:
            1#ifdef _AFXDLL
            2    #define DECLARE_DYNAMIC(class_name) \
            3    protected: \
            4        static CRuntimeClass* PASCAL _GetBaseClass(); \
            5    public: \
            6        static const CRuntimeClass class##class_name; \
            7        static CRuntimeClass* PASCAL GetThisClass(); \
            8        virtual CRuntimeClass* GetRuntimeClass() const; \
            so the result(DECLARE_DYNCREATE(CDynamicDoc)) of combining the above two is following:
            1protected
            2        static CRuntimeClass* PASCAL _GetBaseClass(); 
            3    public
            4        static const CRuntimeClass classCDynamicDoc; 
            5        static CRuntimeClass* PASCAL GetThisClass(); 
            6        virtual CRuntimeClass* GetRuntimeClass() const
            7        static CObject* PASCAL CreateObject();

            2、展開CDynamicDoc.cpp中的IMPLEMENT_DYNCREATE(CDynamicDoc, CDocument):
            1#define IMPLEMENT_DYNCREATE(class_name, base_class_name) \
            2    CObject* PASCAL class_name::CreateObject() \
            3        return new class_name; } \
            4    IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, \
            5        class_name::CreateObject, NULL)
            4.1如下定義:
             1#define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew, class_init) \
             2    CRuntimeClass* PASCAL class_name::_GetBaseClass() \
             3        return RUNTIME_CLASS(base_class_name); } \
             4    AFX_COMDAT const CRuntimeClass class_name::class##class_name = { \
             5        #class_name, sizeof(class class_name), wSchema, pfnNew, \
             6            &class_name::_GetBaseClass, NULL, class_init }
            ; \
             7    CRuntimeClass* PASCAL class_name::GetThisClass() \
             8        return _RUNTIME_CLASS(class_name); } \
             9    CRuntimeClass* class_name::GetRuntimeClass() const \
            10        return _RUNTIME_CLASS(class_name); } \
            4.1.2 CRuntimeClass如下定義:
             1struct CRuntimeClass
             2    {
             3    // Attributes
             4        LPCSTR m_lpszClassName;
             5        int m_nObjectSize;
             6        UINT m_wSchema; // schema number of the loaded class
             7        CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class
             8    #ifdef _AFXDLL
             9        CRuntimeClass* (PASCAL* m_pfnGetBaseClass)();
            10    #else
            11        CRuntimeClass* m_pBaseClass;
            12    #endif
            13
            14    // Operations
            15        CObject* CreateObject();
            16        BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const;
            17
            18        // dynamic name lookup and creation
            19        static CRuntimeClass* PASCAL FromName(LPCSTR lpszClassName);
            20        static CRuntimeClass* PASCAL FromName(LPCWSTR lpszClassName);
            21        static CObject* PASCAL CreateObject(LPCSTR lpszClassName);
            22        static CObject* PASCAL CreateObject(LPCWSTR lpszClassName);
            23
            24    // Implementation
            25        void Store(CArchive& ar) const;
            26        static CRuntimeClass* PASCAL Load(CArchive& ar, UINT* pwSchemaNum);
            27
            28        // CRuntimeClass objects linked together in simple list
            29        CRuntimeClass* m_pNextClass;       // linked list of registered classes
            30        const AFX_CLASSINIT* m_pClassInit;
            31    }
            ;
            4.1.2.30 AFX_CLASSINIT如下定義:(這個變量非常重要,它完成了將新的類加在List頭部的功能,List中的節點類型就是CRuntimeClass)
             1/////////////////////////////////////////////////////////////////////////////
             2    // Basic object model
             3
             4    // generate static object constructor for class registration
             5    void AFXAPI AfxClassInit(CRuntimeClass* pNewClass);
             6    struct AFX_CLASSINIT
             7        { AFX_CLASSINIT(CRuntimeClass* pNewClass) { AfxClassInit(pNewClass); } };
             8    //C:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\src\mfc\objcore.cpp Line157
             9    void AFXAPI AfxClassInit(CRuntimeClass* pNewClass)
            10    {
            11        AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
            12        AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
            13        pModuleState->m_classList.AddHead(pNewClass);
            14        AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
            15    }

            16    //可以將AfxClassInit()函數的功能簡單的如下表示:
            17    AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass* pNewClass)
            18    {
            19        pNewClass->m_pNextClass = CRuntimeClass::pFirstClass;
            20        CRuntimeClass::pFirstClass = pNewClass;
            21    }

            4.1.3 RUNTIME_CLASS如下定義:
            1#define RUNTIME_CLASS(class_name) (class_name::GetThisClass())
            4.1.4 AFX_COMDAT如下定義:
            1#define AFX_COMDAT __declspec(selectany)
            說明:“#”——operator (#) converts macro parameters to string literals without expanding the parameter definition.
            “##”——operator (##), which is sometimes called the "merging" operator, is used in both object-like and function-like macros.
            4.1.8 _RUNTIME_CLASS如下定義:
            1#define _RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))
            so the result(IMPLEMENT_DYNCREATE(CDynamicDoc, CDocument)) of combining the aboves is following:
             1//CDynamicDoc, CDocument->class_name, base_class_name
             2  static  CObject* PASCAL CDynamicDoc::CreateObject()
             
            3    
             
            4        return new CDynamicDoc; 
             
            5    }

             
            6
             
            7    static CRuntimeClass* PASCAL CDynamicDoc::_GetBaseClass()
             
            8    
             
            9        return CDocument::GetThisClass()
            10    }

            11
            12    __declspec(selectany) static const CRuntimeClass CDynamicDoc::classCDynamicDoc = 
            13    {
            14        "CDynamicDoc"
            15        , sizeof(class CDynamicDoc)
            16        , 0xFFFF
            17        , CDynamicDoc::CreateObject
            18        , &CDynamicDoc::_GetBaseClass
            19        , NULL
            20        , NULL
            21    }
            ;
            22
            23    static CRuntimeClass* PASCAL CDynamicDoc::GetThisClass()
            24    {
            25        return ((CRuntimeClass*)(&CDynamicDoc::classCDynamicDoc));
            26    }

            27
            28    CRuntimeClass* CDynamicDoc::GetRuntimeClass() const
            29    {
            30        return ((CRuntimeClass*)(&CDynamicDoc::classCDynamicDoc));
            31    }
            小結:注意了,上面的成員變量、很多函數都是static
            如果你想看這些宏的簡化版,可以參考侯老的《深入淺出MFC》,如下:

             1//in header file
             2class CView : public CWnd
             3{
             4public:
             5    static CRuntimeClass classCView;
             6    virtual CRuntimeClass* GetRuntimeClass() const;
             7    //……
             8}
            ;
             9//in implementation file
            10static char_lpszCView = "CView";
            11CRuntimeClass CView::classCView =
            12{
            13    _lpszCView
            14    , sizeof(CView)
            15    , 0xFFF
            16    , NULL
            17    , &CWnd::classCWnd
            18    , NULL
            19}
            ;
            20static AFX_CLASSINIT _init_CView(&CView::classCView)
            21{
            22    (&CView::classCView)->m_pNextClass = CRuntimeClass::pFirstClass;
            23    CRuntimeClass::pFirstClass = &CView::classCView;
            24}

            25CRuntimeClass* CView::GetRuntimeClass() const
            26{
            27    return &CView::classCView;
            28}
            其中他將CRuntimeClass簡化定義為:
            struct CRuntimeClass
            {
            // Attributes
                    LPCSTR m_lpszClassName;
                    int m_nObjectSize;
                    UINT m_wSchema; // schema number of the loaded class
                    CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class
                    CRuntimeClass* m_pBaseClass;

                    // CRuntimeClass objects linked together in simple list
                    static CRuntimeClass* pFirstClass; // start of class list
                    CRuntimeClass* m_pNextClass;       // linked list of registered classes
            };

            三、宏DECLARE_SERIAL(CStroke)、IMPLEMENT_SERIAL(CStroke, CObject, 1),給出它們的宏定義及結果:
             1//declaration file
             2#define DECLARE_SERIAL(class_name) \
             3    _DECLARE_DYNCREATE(class_name) \
             4    AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb);
             5
             6    #define _DECLARE_DYNCREATE(class_name) \
             7    _DECLARE_DYNAMIC(class_name) \
             8    static CObject* PASCAL CreateObject();
             9
            10    #define _DECLARE_DYNAMIC(class_name) \
            11    protected: \
            12        static CRuntimeClass* PASCAL _GetBaseClass(); \
            13    public: \
            14        static CRuntimeClass class##class_name; \
            15        static CRuntimeClass* PASCAL GetThisClass(); \
            16        virtual CRuntimeClass* GetRuntimeClass() const; \
            17//implement file
            18#define IMPLEMENT_SERIAL(class_name, base_class_name, wSchema) \
            19    CObject* PASCAL class_name::CreateObject() \
            20        return new class_name; } \
            21    extern AFX_CLASSINIT _init_##class_name; \
            22    _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, \
            23        class_name::CreateObject, &_init_##class_name) \
            24    AFX_CLASSINIT _init_##class_name(RUNTIME_CLASS(class_name)); \
            25    CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb) \
            26        { pOb = (class_name*) ar.ReadObject(RUNTIME_CLASS(class_name)); \
            27            return ar; }
             \
            28    
            29    // generate static object constructor for class registration
            30    void AFXAPI AfxClassInit(CRuntimeClass* pNewClass);
            31    struct AFX_CLASSINIT
            32        { AFX_CLASSINIT(CRuntimeClass* pNewClass) { AfxClassInit(pNewClass); } };
            33
            34    void AFXAPI AfxClassInit(CRuntimeClass* pNewClass)
            35    {
            36        AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
            37        AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
            38        pModuleState->m_classList.AddHead(pNewClass);
            39        AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
            40    }

            41
            42    
            43    #define _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew, class_init) \
            44    CRuntimeClass* PASCAL class_name::_GetBaseClass() \
            45        return RUNTIME_CLASS(base_class_name); } \
            46    AFX_COMDAT CRuntimeClass class_name::class##class_name = { \
            47        #class_name, sizeof(class class_name), wSchema, pfnNew, \
            48            &class_name::_GetBaseClass, NULL, class_init }
            ; \
            49    CRuntimeClass* PASCAL class_name::GetThisClass() \
            50        return _RUNTIME_CLASS(class_name); } \
            51    CRuntimeClass* class_name::GetRuntimeClass() const \
            52        return _RUNTIME_CLASS(class_name); } \
            53    
            54    #define _RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))
            55
            56    #define RUNTIME_CLASS(class_name) (class_name::GetThisClass())

             1//header file
             2    protected
             3        static CRuntimeClass* PASCAL _GetBaseClass(); 
             4    public
             5        static CRuntimeClass classCStroke; 
             6        static CRuntimeClass* PASCAL GetThisClass(); 
             7        virtual CRuntimeClass* GetRuntimeClass() const
             8        static CObject* PASCAL CreateObject();
             9        AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, CStroke* &pOb);
            10//implement file
            11    //static
            12    static CObject* PASCAL CStroke::CreateObject()
            13    {
            14        return new CStroke;
            15    }

            16    //static
            17    static CRuntimeClass* PASCAL CStroke::GetThisClass();
            18    
            19        return ((CRuntimeClass*)(&CStroke::classCStroke))
            20    }

            21    //static
            22    static CRuntimeClass* PASCAL CStroke::_GetBaseClass() 
            23    
            24        return (CObject::GetThisClass());
            25    }

            26    //static
            27    static AFX_COMDAT CRuntimeClass CStroke::classCStroke = 
            28    {
            29        "CStroke"
            30        , sizeof(class CStroke)
            31        , 1
            32        , CStroke::CreateObject
            33        , &class_name::_GetBaseClass
            34        , NULL
            35        , &_init_CStroke 
            36    }

            37    CRuntimeClass* CStroke::GetRuntimeClass() const
            38    
            39        return ((CRuntimeClass*)(&CStroke::classCStroke)); 
            40    }

            41    extern struct AFX_CLASSINIT _init_CStroke;
            42    struct AFX_CLASSINIT _init_CStroke
            43    {
            44        void AFXAPI AfxClassInit(CRuntimeClass* CStroke)
            45        {
            46            AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
            47            AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
            48            pModuleState->m_classList.AddHead(CStroke);
            49            AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
            50        }

            51    }
            ;
            52    CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb) 
            53    
            54        pOb = (CStroke*) ar.ReadObject(RUNTIME_CLASS(CStroke));
            55        return ar; 
            56    }
            總結,一旦RUNTIME_CLASS(CStroke)由#define RUNTIME_CLASS(class_name) (class_name::GetThisClass())也就是CStroke::GetThisClass() 即
            CStroke::classCStroke =
             {
              "CStroke"
              , sizeof(class CStroke)
              , 1
              , CStroke::CreateObject
              , &class_name::_GetBaseClass
              , NULL
              , &_init_CStroke
             }
            其中,由extern AFX_CLASSINIT _initCStroke可知_init_CStroke是一個結構體AFX_CLASSINIT的對象,此結構體有構造函數:
             1void AFXAPI AfxClassInit(CRuntimeClass* pNewClass);
             2    struct AFX_CLASSINIT
             3        { AFX_CLASSINIT(CRuntimeClass* pNewClass) { AfxClassInit(pNewClass); } };
             4
             5    void AFXAPI AfxClassInit(CRuntimeClass* pNewClass)
             6    {
             7        AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
             8        AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
             9        pModuleState->m_classList.AddHead(pNewClass);
            10        AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
            11    }
            所以一旦返回classCStroke,也就調用了_init_CStroke的構造函數即將類CStroke添加到了全局變量m_classList類的List中了,同時在變量classCStroke中,也可以得到類CStroke的名稱、大小、一個CStroke的對象、類CStroke的基類以及AFX_CLASSINIT結構的一個對象。
            posted on 2010-10-26 12:00 心羽 閱讀(1569) 評論(0)  編輯 收藏 引用 所屬分類: 需求分析
            久久亚洲精品视频| 久久天堂电影网| 欧洲精品久久久av无码电影 | 久久99精品久久久久久久久久| 亚洲AV无码久久精品蜜桃| 国产69精品久久久久777| 国产精品久久久久久久午夜片| 欧美粉嫩小泬久久久久久久 | 日产精品久久久久久久| 精品久久久久香蕉网| 一本大道加勒比久久综合| 亚洲欧美日韩精品久久亚洲区 | 国产精品久久影院| 亚洲国产成人精品91久久久| 久久精品毛片免费观看| 婷婷久久综合九色综合绿巨人 | 午夜不卡888久久| 色妞色综合久久夜夜| 99久久国产主播综合精品| 中文字幕无码免费久久| 国产精品综合久久第一页| 精品久久人妻av中文字幕| 99精品久久久久久久婷婷| 国内精品免费久久影院| 亚洲va中文字幕无码久久| 精品国产日韩久久亚洲| 久久精品视频91| 久久精品国产亚洲一区二区三区| 精品国产91久久久久久久| 亚洲国产另类久久久精品黑人 | 2021少妇久久久久久久久久| 99久久夜色精品国产网站| 亚洲日本va午夜中文字幕久久| 99久久亚洲综合精品网站| 97久久精品无码一区二区天美 | 久久久久人妻一区二区三区vr| 精品久久久久久国产| 久久精品卫校国产小美女| 国内精品九九久久精品| 亚洲精品无码久久久久去q| 一本色道久久99一综合|