1、宏就是用宏定義指令#define定義一個標識符,用它來表示一個字符串或一段源代碼。
MFC宏作為MFC類庫的一個組成部分在MFC應用程序中經常出現。
MFC宏在路徑
".../Microsoft Visual Studio/VC/atlmfc/include"
下的Afxwin.h、Afx.h及Afxmsg_.h等MFC頭文件中分別進行了定義。
(1)常用的MFC宏
包括消息映射宏、運行時類型識別宏、序列化宏、調試宏和異常宏等。
要想真正了解MFC的內部機制和熟練運用MFC,必須掌握MFC宏的基本原理和使用方法。
(2)有關運行時類型識別的宏
運行時類型識別(RTTI)是指在程序運行時能夠確定一個對象的類型。
MFC擴充了一般C++中運行時類型識別的功能,當一個類支持MFC的運行時類型識別功能時,它允許程序獲取對象的信息(如類名、所占存儲空間大小及版本號等)和基類信息(RTCI)。
1.運行時基礎宏:RUNTIME_CLASS(class_name)
返回參數class_name所指定類的靜態成員變量class##class_name的指針,該指針指向一個CRuntime結構。
宏定義如下:
#define RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))
程序能夠利用RUNTIME_CLASS宏實時創建類的實例。
為了讓這個宏起作用,定義的類必須是類CObject的派生類,並且在派生類的定義中必須使用宏DECLARE_DYNAMIC、DECLARE_DYNCREATE或DECLARE_SERIAL,
在派生類的實現源文件中使用宏IMPLEMENT_DYNAMIC、IMPLEMENT_DYNCREATE或IMPLEMENT_SERIAL。
這三個宏使MFC類及其派生類具有三個不同等級的功能。
2.動態支持宏:DECLARE_DYNAMIC(class_name)和IMPELMENT_DYNAMIC(class_name,base_class_name)
使用動態支持宏能夠使CObject派生類的對象具有基本的類型識別機能,可以通過調用成員函數CObject::IsKindOf(ClassName)測試對象與給定類Class_Name的關系。
DECLARE_DYNAMIC()宏定義如下:
#define DECLARE_DYNAMIC(class_name) \ public: \ static const CRuntimeClass class##class_name; \ virtual CRuntimeClass* GetRuntimeClass() const; \
例1: 定義一個類MyClass,使用RUNTIME_CLASS()宏的基本對象識別功能
//在頭文件MyClass.h class CMyClass:public CObject { DECLARE_DYNAMIC(CMyClass) public: void someFunction(void); }; //在實現源文件MyClass.cpp中 #include "MyClass.h" IMPLEMENT_DYNAMIC(CMyClass,CObject) void CMyClass::SomeFunction(void) { CObject* pObject=new CMyClass; if(pObject->IsKindOf(RUNTIME_CLASS(CMyClass))) { CMyClass* pMyObject=(CMyClass*)pObject; AfxMessageBox("MyObject is an object of the class CMyClass"); } else AfxMessageBox("MyObject is not an object of the class CMyClass"); delete pObject; }
3.動態創建宏:DECLARE_DYNCREATE(class_name)和 IMPLEMENT_DYNCREATE(class_name,base_class_name)
動態創建是動態支持的一個超集,除了基本的類型識別機能,使用動態創建宏能夠使CObject類的派生類具有運行時動態創建對象的功能。
注意,支持動態創建的類必須有一個默認的不帶參數的構造函數,用於一個穩定的對象。
MFC應用程序框架利用這個機能動態創建新的對象。
例如,當序列化期間從磁盤讀取一個對象時,應用程序框架將利用文檔類、視圖類和框類的動態創建功能業動態創建它們的運行時對象。
在MFC應用程序框架中,向導為MFC派生類自動添加了這兩個動態創建宏。
4.序列化:DECLARE_SERIAL()和IMPLEMENT_SERIAL()
序列化是動態支持和動態創建的一個超集,除了基本的類別識別和動態創建機能,使用序列化宏能夠使CObject類的派生類具有實現對象持久性的序列化功能。
MFC調試宏
1.TRACE跟蹤聲明宏
TRACE()宏語法說明如下:
TRACE(<輸出格式>,<表達式>)
其中的參數是由輸出格式和表達式組成,其形式與函數printf()的參數一樣。
TRACE宏的功能是在調試運行時把表達式的值輸出到Output調試窗口。
TRACE宏只在MFC應用程序Debug版的調試運行狀態下才起作用,並且必須保證在Developer Studio中的Enable tracing設置,這需要執行Tools|MFC Tracer命令。
例2 對於以下代碼:
char* szName="LiMing"; int nAge=18; TRACE("Name=%s,Age=%",szName,nAge); 調試運行時在Ouput窗口將輸出以下內容: Name=LiMing,Age=18
2.ASSERT斷言宏
ASSERT(<表達式>)
當執行該宏時,如果表達式為真,則程序繼續執行;否則暫停程序的運行,並彈出一個對話框,告訴用戶程序暫停運行的行及所在文件的信息。用戶可選擇終止運行、調試程序或繼續運行。
例如,在視圖派生類的成員函數GetDocument()中,MFC使用了ASSERT()宏判斷當前文檔是否是運行時類的對象。
例3 :設已自定義一個名為CMyFrame的框架窗口類,它也是CFrameWnd的派生類。在程序中構建一個與CMyFrame相關聯的文檔模板對象,並為構建的文檔模板創建框架窗口。然后可以編寫如下代碼使用這個框架窗口。
CMyFrame* pFrame=(CMyFrame*)AfxGetMainWnd(); ASSERT(pFrame->IsKindOf(RUNTIME_CLASS(CMyFrame))); //判斷pFrame的類型 pFrame->DoSomeOperation(); //調用成員函數完成某些操作
AfxGetMainWnd()是一個全局函數,返回值向應用程序主窗口的指針,類型為CWnd*,因此必須對它進行強制類型轉換。但如何知道是否轉換成功?
CMyFrame類也是CObject的派生類,可以結合成員函數IsKindOf()使用ASSERT()宏來檢查pFrame的類型。
在pFrame->DoSomeOperation()語句之前插入ASSERT()宏,就可以在運行機制時做類型檢查,當類型不匹配時,引發一個斷方,可以中斷程序執行。
ASSERT宏只在Debug版本中才起作用,它在Release版本中是不會被編譯的,
在Release版本中可以使用VERIFY宏。VERIFY宏與ASSERT宏在Debug版本中的作用一致,
區別在於在Release版本中VERIFY宏仍然有效,它會對參數表達式求值,但不管結果如何都不會暫停程序的運行。
為了避免給程序帶來不良的后果,使用ASSERT宏時必須保證參數表達式中不能有函數調用語句,
因為ASSERT宏中的函數調用語句在Release版本中根本不在。
出現這種情況時,可以使用VERIFY宏取代ASSERT宏。
3.ASSERT_VALID斷言有效宏
ASSERT_VALID()宏語法說明如下:
ASSERT_VALID(<指針>)
ASSERT_VALID宏用於檢查指針和對象的有效性。對於一般指針,只檢查指針是否為空。
對於MFC類對象指針,通過調用CObject類的成員函數AssertValid()判斷對象的舍法性。
ASSERT_VALID宏提示指針或對象無效的方式與ASSERT宏一樣,彈出一個信息對話框。
ASSERT_VALID宏也是只在Debug版本中才起作用。