今天上来有N小时了,居然发现没一个适用偶回答的问题.看来水平不行,须得多加努力.
郁闷之余,发小贴一张,资高手牛人探讨.如版猪大人有幸路过,请为置顶,在下感激不尽!检查CView的源代码ViewCore.cpp时,在文件尾发现这样几行:
// IMPLEMENT_DYNAMIC for CView is in wincore.cpp for .OBJ granularity reasons
IMPLEMENT_DYNAMIC(CSplitterWnd, CWnd) // for swap tuning
IMPLEMENT_DYNAMIC(CCtrlView, CView)
在这里,IMPLEMENT_DYNAMIC和文件的内容并不匹配.事实上,该文件中仅包含了视图类的主要实现部分和CCtrlView的部分实现,但绝对没有CSplitterWnd的实现.想像中本该存在于此的IMPLEMENT_DYNCREATE(CFrameWnd, CWnd)却没有出现,经查找发现它位于WinFrm.cpp文件尾(该文件主要实现框架类CFrameWnd):
// in this file for IsKindOf library granularity (IsKindOf references these)
IMPLEMENT_DYNCREATE(CFrameWnd, CWnd)
IMPLEMENT_DYNAMIC(CView, CWnd)
现在的问题是:MFC这样将IMPLEMENT_DYNAMIC放在看似随意的文件中的目的是什么呢?
郁闷之余,发小贴一张,资高手牛人探讨.如版猪大人有幸路过,请为置顶,在下感激不尽!检查CView的源代码ViewCore.cpp时,在文件尾发现这样几行:
// IMPLEMENT_DYNAMIC for CView is in wincore.cpp for .OBJ granularity reasons
IMPLEMENT_DYNAMIC(CSplitterWnd, CWnd) // for swap tuning
IMPLEMENT_DYNAMIC(CCtrlView, CView)
在这里,IMPLEMENT_DYNAMIC和文件的内容并不匹配.事实上,该文件中仅包含了视图类的主要实现部分和CCtrlView的部分实现,但绝对没有CSplitterWnd的实现.想像中本该存在于此的IMPLEMENT_DYNCREATE(CFrameWnd, CWnd)却没有出现,经查找发现它位于WinFrm.cpp文件尾(该文件主要实现框架类CFrameWnd):
// in this file for IsKindOf library granularity (IsKindOf references these)
IMPLEMENT_DYNCREATE(CFrameWnd, CWnd)
IMPLEMENT_DYNAMIC(CView, CWnd)
现在的问题是:MFC这样将IMPLEMENT_DYNAMIC放在看似随意的文件中的目的是什么呢?
解决方案 »
- 关于窗口最小化与最大化按钮的实现
- 请教一个问题(头发都白了)
- 做毕业设计,谁能给我一个http连接的阻断源代码啊.
- 请问:关于创建位图的问题
- 请大家看看我的这段代码,向其他的一个进程写入一个线程函数地址和参数地址,然后启动线程,但是对方进程立刻就报错退出了,为什么,哪里
- 谁有9X下进入RING0 来HOOK API的源码?[急求中]up有分!!
- 100分啊!!谁用过Viavoice 8.0请进来!
- cap视频捕捉的问题,capSetCallbackOnFrame()设置的回调,回调函数中的VIDEOHDR结构中的,lpData参数是不是就是一个位图信息?
- 注册表中的%System%这样的东西如何转换为路径
- 对话框怎么没有地方设置图标呀?
- 请教各位大虾,怎样把一个mpeg视屏文件转化为一个avi格式的文件
- 使用过“activeskin”的进
----------------------------------------------------------------------------
为什么说“看似随意的文件”呢?什么语句放在什么地方必定是有道理的。你要Split View,总不能让一个View自个儿完成切分自已并实现、管理切分出来的新类吧,要知道,切分完之后,分成的几个VIEW都应是平级的,谁也不比谁 的Level高,那么如何调度呢,谁来调度呢,肯定要由比他们Level高一点的来做,它就是框架窗体CFrameWnd.
类信息,
和序列化支持
典型的用法如:
m_pViewModule[Programer_Edit] = CreateView(RUNTIME_CLASS(CProgramer_EditView));
CWnd* CMainFrame::CreateView(CRuntimeClass * pViewClass)
{
ASSERT(pViewClass);
CWnd* pWnd;
TRY
{
pWnd = (CWnd*)pViewClass->CreateObject();
if (pWnd == NULL)
AfxThrowMemoryException();
}
CATCH_ALL(e)
{
TRACE0("Out of memory creating a splitter pane.\n");
return NULL;
}
END_CATCH_ALL
ASSERT_KINDOF(CWnd, pWnd);
ASSERT(pWnd->m_hWnd == NULL); // not yet created
DWORD dwStyle = AFX_WS_DEFAULT_VIEW;
if (afxData.bWin4)
dwStyle &= ~WS_BORDER;
static i=0;
// Create with the right size (wrong position)
CRect rect(CPoint(0,0), CPoint(0,0));
if (!pWnd->Create(NULL, NULL, dwStyle,
rect, &m_wndSplitter2, 1700+i, NULL))
{
TRACE0("Warning: couldn't create client pane for splitter.\n");
// pWnd will be cleaned up by PostNcDestroy
return NULL;
}
i++;
pWnd->SendMessage(WM_INITIALUPDATE);
return pWnd;
}
一个是在头文件,一个是在cpp里。
这个宏只是一个包装宏,是其他几个的组合
DECLARE_DYNCREATE 和 IMPLEMENT_DYNCREATE:
#define DECLARE_DYNCREATE(class_name) DECLARE_DYNAMIC(class_name) static CObject* PASCAL CreateObject();
#define IMPLEMENT_DYNCREATE(class_name, base_class_name) CObject* PASCAL class_name::CreateObject() { return new class_name; } _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, class_name::CreateObject)
於是,以CFrameWnd 為例,㆘列程式碼:
// in header file
class CFrameWnd : public CWnd
{
DECLARE_DYNCREATE(CFrameWnd)
...
};
// in implementation file
IMPLEMENT_DYNCREATE(CFrameWnd, CWnd)
就被展開如㆘(注意,編譯器選項 /P 可得前置處理結果):
// in header file
class CFrameWnd : public CWnd
{
public:
static CRuntimeClass classCFrameWnd;
virtual CRuntimeClass* GetRuntimeClass() const;
static CObject* PASCAL CreateObject();
...
};
// in implementation file
CObject* PASCAL CFrameWnd::CreateObject()
{ return new CFrameWnd; }
static char _lpszCFrameWnd[] = "CFrameWnd";
CRuntimeClass CFrameWnd::classCFrameWnd = {
_lpszCFrameWnd, sizeof(CFrameWnd), 0xFFFF, CFrameWnd::CreateObject,
RUNTIME_CLASS(CWnd), NULL };
static AFX_CLASSINIT _init_CFrameWnd(&CFrameWnd::classCFrameWnd);
CRuntimeClass* CFrameWnd::GetRuntimeClass() const
{ return &CFrameWnd::classCFrameWnd; }
圖示如㆘:
“ C O b je c t ”
C O b je c t : :c la s s C O b je c t
m _ p B a s e C la s s
m _ p N e x tC la s s
“C C m d T a rg e t”
C C m d T a rg e t: : c la s s C C m d T a rg e t
m _ p B a s e C la s s
m _ p N e x tC la s s
“C W in T h re a d ”
C W in T h re a d : :c la s s C W in T h r e a d
m _ p B a s e C la s s
m _ p N e x tC la s s
“C W n d ”
C W n d : : c la s s C W n d
m _ p B a s e C la s s
m _ p N e x tC la s s
“C W in A p p ”
C W in A p p ::c la s s C W in A p p
m _ p B a s e C la s s
m _ p N e x tC la s s
N U L L
C R u n t im e C la s s ::p F ir s tC la s s
N U L L
“C F ra m e W n d ”
C F ram eW n d ::c la s s C F ram eW n d
m _ p B a s e C la s s
m _ p N e x tC la s s
“ C D o c u m e n t ”
C D o c u m e n t : :c la s s C D o c u m e n t
m _ p B a s e C la s s
m _ p N e x tC la s s
“ C V ie w ”
C V ie w : :c la s s C V ie w
m _ p B a s e C la s s
m _ p N e x tC la s s
( s t a t i c 變數)
「物件生成器」CreateObject 函式很簡單,只要說 new 就好。
從巨集的定義我們很清楚可以看出,擁有動態生成(Dynamic Creation)能力的類別庫,
必然亦擁有執行時期型態識別(RTTI)能力,因為 _DYNCREATE 巨集涵蓋了 _DYNAMIC
巨集。
注意:以㆘範例直接跳到 Frame6。本書第㆒版有㆒個 Frame5 程式,用以模擬 MFC 2.5
對動態生成的作法。往事已矣,讀者曾經來函表示沒有必要提過去的東西,徒增腦力負
荷。我想也是,況且 MFC 4.x 的作法更好更容易瞭解,所以我把 Frame5 拿掉了,但仍
保留著序號。
class CObject
{
...
};
class CCmdTarget : public CObject
{
DECLARE_DYNAMIC(CCmdTarget)
...
};
class CWinThread : public CCmdTarget
{
DECLARE_DYNAMIC(CWinThread)
...
};
class CWinApp : public CWinThread
{
DECLARE_DYNAMIC(CWinApp)
...
};
class CDocument : public CCmdTarget
{
DECLARE_DYNAMIC(CDocument)
...
};
class CWnd : public CCmdTarget
{
DECLARE_DYNCREATE(CWnd)
...
};
class CFrameWnd : public CWnd
{
DECLARE_DYNCREATE(CFrameWnd)
...
};
class CView : public CWnd
{
DECLARE_DYNAMIC(CView)
...
};
class CMyWinApp : public CWinApp
{
...
};
class CMyFrameWnd : public CFrameWnd
{
DECLARE_DYNCREATE(CMyFrameWnd)
...
};
class CMyDoc : public CDocument
{
DECLARE_DYNCREATE(CMyDoc)
...
};
class CMyView : public CView
{
DECLARE_DYNCREATE(CMyView)
...
};
在 .cpp 檔㆗又有這些動作:
IMPLEMENT_DYNAMIC(CCmdTarget, CObject)
IMPLEMENT_DYNAMIC(CWinThread, CCmdTarget)
IMPLEMENT_DYNAMIC(CWinApp, CWinThread)
IMPLEMENT_DYNCREATE(CWnd, CCmdTarget)
IMPLEMENT_DYNCREATE(CFrameWnd, CWnd)
IMPLEMENT_DYNAMIC(CDocument, CCmdTarget)
IMPLEMENT_DYNAMIC(CView, CWnd)
IMPLEMENT_DYNCREATE(CMyFrameWnd, CFrameWnd)
IMPLEMENT_DYNCREATE(CMyDoc, CDocument)
IMPLEMENT_DYNCREATE(CMyView, CView)
於是組織出圖3-2 這樣㆒個大網。
現在,我們開始模擬動態生成。首先在 main 函式㆗加㆖這㆒段碼:
void main()
{
...
//Test Dynamic Creation
CRuntimeClass* pClassRef;
CObject* pOb;
while(1)
{
if ((pClassRef = CRuntimeClass::Load()) == NULL)
break;
pOb = pClassRef->CreateObject();
if (pOb != NULL)
pOb->SayHello();
}
}
並設計 CRuntimeClass::CreateObject 和 CRuntimeClass::Load 如㆘:
// in implementation file
CObject* CRuntimeClass::CreateObject()
{
if (m_pfnCreateObject == NULL)
{
TRACE1("Error: Trying to create object which is not "
"DECLARE_DYNCREATE \nor DECLARE_SERIAL: %hs.\n",
m_lpszClassName);
return NULL;
}
CObject* pObject = NULL;
pObject = (*m_pfnCreateObject)();
return pObject;
}
CRuntimeClass* PASCAL CRuntimeClass::Load()
{
char szClassName[64];
CRuntimeClass* pClass;
// JJHOU : instead of Load from file, we Load from cin.
cout << "enter a class name... ";
cin >> szClassName;
for (pClass = pFirstClass; pClass != NULL; pClass = pClass->m_pNextClass)
{
if (strcmp(szClassName, pClass->m_lpszClassName) == 0)
return pClass;
}
TRACE1("Error: Class not found: %s \n", szClassName);
return NULL; // not found
}
然後,為了驗證這樣的動態生成機制的確有效(也就是物件的確被產生了),我讓許多
個類別的建構式都輸出㆒段文字,而且在取得物件指標後,真的去呼叫該物件的㆒個成
員函式 SayHello。我把 SayHello 設計為虛擬函式,所以根據不同的物件型態,會呼叫
到不同的 SayHello 函式,出現不同的輸出字串。
請注意,main 函式㆗的 while 迴路必須等到 CRuntimeClass::Load 傳回 NULL 才會停
止,而 CRuntimeClass::Load 是在它從整個「類別型錄網」㆗找不到它要找的那個類別
名稱時,才傳回 NULL。這些都是我為了模擬與示範,所採取的權宜設計。
Frame6 的命令列編譯聯結動作是(環境變數必須先設定好,請參考第4章的「安裝與設
定」㆒節):
cl my.cpp mfc.cpp <Enter>
㆘面是Frame6 的執行結果。粗體表示我(程式執行者)在螢幕㆖輸入的類別名稱:
enter a class name... CObject
Error: Trying to create object which is not DECLARE_DYNCREATE
or DECLARE_SERIAL: CObject.
enter a class name... CView
Error: Trying to create object which is not DECLARE_DYNCREATE
or DECLARE_SERIAL: CView.
enter a class name... CMyView
CWnd Constructor
CMyView Constructor
Hello CMyView
enter a class name... CMyFrameWnd
CWnd Constructor
CFrameWnd Constructor
CMyFrameWnd Constructor
Hello CMyFrameWnd
enter a class name... CMyDoc
CMyDoc Constructor
Hello CMyDoc
enter a class name... CWinApp
Error: Trying to create object which is not DECLARE_DYNCREATE
or DECLARE_SERIAL: CWinApp.
enter a class name... CJjhou (故意輸入㆒個不在「類別型錄網」㆗的類別名稱)
Error: Class not found: CJjhou (程式結束)
#0001 #define BOOL int
#0002 #define TRUE 1
#0003 #define FALSE 0
#0004 #define LPCSTR LPSTR
#0005 typedef char* LPSTR;
#0006 #define UINT int
#0007 #define PASCAL _stdcall
#0008 #define TRACE1 printf
#0009
#0010 #include <iostream.h>
#0011 #include <stdio.h>
#0012 #include <string.h>
#0013
#0014 class CObject;
#0015
#0016 struct CRuntimeClass
#0017 {
#0018 // Attributes
#0019 LPCSTR m_lpszClassName;
#0020 int m_nObjectSize;
#0021 UINT m_wSchema; // schema number of the loaded class
#0022 CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class
#0023 CRuntimeClass* m_pBaseClass;
#0024
#0025 CObject* CreateObject();
#0026 static CRuntimeClass* PASCAL Load();
#0027
#0028 // CRuntimeClass objects linked together in simple list
#0029 static CRuntimeClass* pFirstClass; // start of class list
#0030 CRuntimeClass* m_pNextClass; // linked list of registered classes
#0031 };
#0032
#0033 struct AFX_CLASSINIT
#0034 { AFX_CLASSINIT(CRuntimeClass* pNewClass); };
#0035
#0036 #define RUNTIME_CLASS(class_name) #0037 (&class_name::class##class_name)
#0038
#0039 #define DECLARE_DYNAMIC(class_name) #0040 public: #0041 static CRuntimeClass class##class_name; #0042 virtual CRuntimeClass* GetRuntimeClass() const;
#0043
#0044 #define DECLARE_DYNCREATE(class_name) #0045 DECLARE_DYNAMIC(class_name) #0046 static CObject* PASCAL CreateObject();
#0047
#0048 #define _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew) #0049 static char _lpsz##class_name[] = #class_name; #0050 CRuntimeClass class_name::class##class_name = { #0051 _lpsz##class_name, sizeof(class_name), wSchema, pfnNew, #0052 RUNTIME_CLASS(base_class_name), NULL }; #0053 static AFX_CLASSINIT _init_##class_name(&class_name::class##class_name); #0054 CRuntimeClass* class_name::GetRuntimeClass() const #0055 { return &class_name::class##class_name; } #0056
#0057 #define IMPLEMENT_DYNAMIC(class_name, base_class_name) #0058 _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL)
#0059
#0060 #define IMPLEMENT_DYNCREATE(class_name, base_class_name) #0061 CObject* PASCAL class_name::CreateObject() #0062 { return new class_name; } #0063 _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, #0064 class_name::CreateObject)
#0065
#0066 class CObject
#0067 {
#0068 public:
#0069 CObject::CObject() {
#0070 }
#0071 CObject::~CObject() {
#0072 }
#0073
#0074 virtual CRuntimeClass* GetRuntimeClass() const;
#0075 BOOL IsKindOf(const CRuntimeClass* pClass) const;
#0076
#0077 public:
#0078 static CRuntimeClass classCObject;
#0079 virtual void SayHello() { cout << "Hello CObject \n"; }
#0080 };
#0081
#0082 class CCmdTarget : public CObject
#0083 {
#0084 DECLARE_DYNAMIC(CCmdTarget)
#0085 public:
#0086 CCmdTarget::CCmdTarget() {
#0087 }
#0088 CCmdTarget::~CCmdTarget() {
#0089 }
#0090 };
#0091
#0092 class CWinThread : public CCmdTarget
#0093 {
#0094 DECLARE_DYNAMIC(CWinThread)
#0095 public:
#0096 CWinThread::CWinThread() {
#0097 }
#0098 CWinThread::~CWinThread() {
#0099 }
#0100
#0101 virtual BOOL InitInstance() {
#0102 return TRUE;
#0103 }
#0104 virtual int Run() {
#0105 return 1;
#0106 }
#0107 };
#0108
#0109 class CWnd;
#0110
#0111 class CWinApp : public CWinThread
#0112 {
#0113 DECLARE_DYNAMIC(CWinApp)
#0114 public:
#0115 CWinApp* m_pCurrentWinApp;
#0116 CWnd* m_pMainWnd;
#0117
#0118 public:
#0119 CWinApp::CWinApp() {
#0120 m_pCurrentWinApp = this;
#0121 }
#0122 CWinApp::~CWinApp() {
#0123 }
#0124
#0125 virtual BOOL InitApplication() {
#0126 return TRUE;
#0127 }
#0128 virtual BOOL InitInstance() {
#0129 return TRUE;
#0130 }
#0131 virtual int Run() {
#0132 return CWinThread::Run();
#0133 }
#0134 };
#0135
#0136
#0137 class CDocument : public CCmdTarget
#0138 {
#0139 DECLARE_DYNAMIC(CDocument)
#0140 public:
#0141 CDocument::CDocument() {
#0142 }
#0143 CDocument::~CDocument() {
#0144 }
#0145 };
#0146
#0147 class CWnd : public CCmdTarget
#0148 {
#0149 DECLARE_DYNCREATE(CWnd)
#0150 public:
#0151 CWnd::CWnd() {
#0152 cout << "CWnd Constructor \n";
#0153 }
#0154 CWnd::~CWnd() {
#0155 }
#0156
#0157 virtual BOOL Create();
#0158 BOOL CreateEx();
#0159 virtual BOOL PreCreateWindow();
#0160 void SayHello() { cout << "Hello CWnd \n"; }
#0161 };
#0162
#0163 class CFrameWnd : public CWnd
#0164 {
#0165 DECLARE_DYNCREATE(CFrameWnd)
#0166 public:
#0167 CFrameWnd::CFrameWnd() {
#0168 cout << "CFrameWnd Constructor \n";
#0169 }
#0170 CFrameWnd::~CFrameWnd() {
#0171 }
#0172 BOOL Create();
#0173 virtual BOOL PreCreateWindow();
#0174 void SayHello() { cout << "Hello CFrameWnd \n"; }
#0175 };
#0176
#0177 class CView : public CWnd
#0178 {
#0179 DECLARE_DYNAMIC(CView)
#0180 public:
#0181 CView::CView() {
#0182 }
#0183 CView::~CView() {
#0184 }
#0185 };
#0186
#0187 // global function
#0188 CWinApp* AfxGetApp();
#0002
#0003 extern CMyWinApp theApp;
#0004
#0005 static char szCObject[] = "CObject";
#0006 struct CRuntimeClass CObject::classCObject =
#0007 { szCObject, sizeof(CObject), 0xffff, NULL, NULL };
#0008 static AFX_CLASSINIT _init_CObject(&CObject::classCObject);
#0009
#0010 CRuntimeClass* CRuntimeClass::pFirstClass = NULL;
#0011
#0012 AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass* pNewClass)
#0013 {
#0014 pNewClass->m_pNextClass = CRuntimeClass::pFirstClass;
#0015 CRuntimeClass::pFirstClass = pNewClass;
#0016 }
#0017
#0018 CObject* CRuntimeClass::CreateObject()
#0019 {
#0020 if (m_pfnCreateObject == NULL)
#0021 {
#0022 TRACE1("Error: Trying to create object which is not "
#0023 "DECLARE_DYNCREATE \nor DECLARE_SERIAL: %hs.\n",
#0024 m_lpszClassName);
#0025 return NULL;
#0026 }
#0027
#0028 CObject* pObject = NULL;
#0029 pObject = (*m_pfnCreateObject)();
#0030
#0031 return pObject;
#0032 }
#0033
#0034 CRuntimeClass* PASCAL CRuntimeClass::Load()
#0035 {
#0036 char szClassName[64];
#0037 CRuntimeClass* pClass;
#0038
#0039 // JJHOU : instead of Load from file, we Load from cin.
#0040 cout << "enter a class name... ";
#0041 cin >> szClassName;
#0042
#0043 for (pClass = pFirstClass; pClass != NULL; pClass = pClass->m_pNextClass)
#0044 {
#0045 if (strcmp(szClassName, pClass->m_lpszClassName) == 0)
#0046 return pClass;
#0047 }
#0048
#0049 TRACE1("Error: Class not found: %s \n", szClassName);
#0050 return NULL; // not found
#0051 }
#0052
#0053 CRuntimeClass* CObject::GetRuntimeClass() const
#0054 {
#0055 return &CObject::classCObject;
#0056 }
#0057
#0058 BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
#0059 {
#0060 CRuntimeClass* pClassThis = GetRuntimeClass();
#0061 while (pClassThis != NULL)
#0062 {
#0063 if (pClassThis == pClass)
#0064 return TRUE;
#0065 pClassThis = pClassThis->m_pBaseClass;
#0066 }
#0067 return FALSE; // walked to the top, no match
#0068 }
#0069
#0070 BOOL CWnd::Create()
#0071 {
#0072 return TRUE;
#0073 }
#0074
#0075 BOOL CWnd::CreateEx()
#0076 {
#0077 PreCreateWindow();
#0078 return TRUE;
#0079 }
#0080
#0081 BOOL CWnd::PreCreateWindow()
#0082 {
#0083 return TRUE;
#0084 }
#0085
#0086 BOOL CFrameWnd::Create()
#0087 {
#0088 CreateEx();
#0089 return TRUE;
#0090 }
#0091
#0092 BOOL CFrameWnd::PreCreateWindow()
#0093 {
#0094 return TRUE;
#0095 }
#0096
#0097 CWinApp* AfxGetApp()
#0098 {
#0099 return theApp.m_pCurrentWinApp;
#0100 }
#0101
#0102 IMPLEMENT_DYNAMIC(CCmdTarget, CObject)
#0103 IMPLEMENT_DYNAMIC(CWinThread, CCmdTarget)
#0104 IMPLEMENT_DYNAMIC(CWinApp, CWinThread)
#0105 IMPLEMENT_DYNAMIC(CDocument, CCmdTarget)
#0106 IMPLEMENT_DYNCREATE(CWnd, CCmdTarget)
#0107 IMPLEMENT_DYNAMIC(CView, CWnd)
#0108 IMPLEMENT_DYNCREATE(CFrameWnd, CWnd)MY.H#0001 #include <iostream.h>
#0002 #include "mfc.h"
#0003
#0004 class CMyWinApp : public CWinApp
#0005 {
#0006 public:
#0007 CMyWinApp::CMyWinApp() {
#0008 }
#0009 CMyWinApp::~CMyWinApp() {
#0010 }
#0011
#0012 virtual BOOL InitInstance();
#0013 };
#0014
#0015 class CMyFrameWnd : public CFrameWnd
#0016 {
#0017 DECLARE_DYNCREATE(CMyFrameWnd)
#0018 public:
#0019 CMyFrameWnd();
#0020 ~CMyFrameWnd() {
#0021 }
#0022 void SayHello() { cout << "Hello CMyFrameWnd \n"; }
#0023 };
#0024
#0025 class CMyDoc : public CDocument
#0026 {
#0027 DECLARE_DYNCREATE(CMyDoc)
#0028 public:
#0029 CMyDoc::CMyDoc() {
#0030 cout << "CMyDoc Constructor \n";
#0031 }
#0032 CMyDoc::~CMyDoc() {
#0033 }
#0034 void SayHello() { cout << "Hello CMyDoc \n"; }
#0035 };
#0036
#0037 class CMyView : public CView
#0038 {
#0039 DECLARE_DYNCREATE(CMyView)
#0040 public:
#0041 CMyView::CMyView() {
#0042 cout << "CMyView Constructor \n";
#0043 }
#0044 CMyView::~CMyView() {
#0045 }
#0046 void SayHello() { cout << "Hello CMyView \n"; }
#0047 };
#0048
#0049 // global function
#0050 void AfxPrintAllClasses();MY.CPP#0001 #include "my.h"
#0002
#0003 CMyWinApp theApp;
#0004
#0005 BOOL CMyWinApp::InitInstance()
#0006 {
#0007 m_pMainWnd = new CMyFrameWnd;
#0008 return TRUE;
#0009 }
#0010
#0011 CMyFrameWnd::CMyFrameWnd()
#0012 {
#0013 cout << "CMyFrameWnd Constructor \n";
#0014 Create();
#0015 }
#0016
#0017 IMPLEMENT_DYNCREATE(CMyFrameWnd, CFrameWnd)
#0018 IMPLEMENT_DYNCREATE(CMyDoc, CDocument)
#0019 IMPLEMENT_DYNCREATE(CMyView, CView)
#0020
#0021 void PrintAllClasses()
#0022 {
#0023 CRuntimeClass* pClass;
#0024
#0025 // just walk through the simple list of registered classes
#0026 for (pClass = CRuntimeClass::pFirstClass; pClass != NULL;
#0027 pClass = pClass->m_pNextClass)
#0028 {
#0029 cout << pClass->m_lpszClassName << "\n";
#0030 cout << pClass->m_nObjectSize << "\n";
#0031 cout << pClass->m_wSchema << "\n";
#0032 }
#0033 }
#0034 //---------------------------------------------------------------
#0035 // main
#0036 //---------------------------------------------------------------
#0037 void main()
#0038 {
#0039 CWinApp* pApp = AfxGetApp();
#0040
#0041 pApp->InitApplication();
#0042 pApp->InitInstance();
#0043 pApp->Run();
#0044
#0045 //Test Dynamic Creation
#0046 CRuntimeClass* pClassRef;
#0047 CObject* pOb;
#0048 while(1)
#0049 {
#0050 if ((pClassRef = CRuntimeClass::Load()) == NULL)
#0051 break;
#0052
#0053 pOb = pClassRef->CreateObject();
#0054 if (pOb != NULL)
#0055 pOb->SayHello();
#0056 }
#0057 }
byf2002(调侃2002) :<深入浅出MFC>那本书没讲这个东西.它只讲了MFC的概念级的原理,从没对这种实现细节有过描述.事实上,它几乎自己实现了一个精简版的MFC,而不是在MS的实现上作的研究.
主要是各种对象view,doc,frame,childframe的交互问题。
在很多对象中都要实现这个功能,而WinFrm.cpp对应的就是mainframe.这是构架决定的。
所以实现定在frm.cpp里
现在猜想,MFC这样做的原因,可能是为了限定单个Obj文件的大小或者按4k边界对齐。
mscf(扎西特勒) :在MSDN的哪部分?我可是半天都没翻出来有这方面的内容.注意题目不是问这个宏的意义与怎么实现.
whoo(谁) :能在微软总部混饭吃的人,不可能那么菜吧?就算不懂.而且如果是随意决定的位置,它就不会在后面加注释进行特别说明.
codewarrior(会思考的草) :你说的好象是边界对齐(alignment)而不是粒度(Granularity)吧?
大多数情况下,链接器和编译器合作完成这些.用/Gy参数编译,每个函数都会放到自己的comdat(对链接器来相当于一个独立的OBJ文件)中.然后用/opt:noref链接,这将削减那些那些从未引用过的comdat,最终使只有引用到的函数的代码少会出现在链接结果中.
但是,当用户有指向函数的non-comdat部分时会出现问题.这些non-comdat部分包括消息表(包含消息处理函数的地址)和类似CRuntimeClass对象的数据(它包含CreateObject函数的地址,该函数会调用用构造函数,构造函数会重新设置vtable(虚表)中的虚函数地址,通过vtable会找到一些用户并没有用到的虚函数).
有可能用户会引用对象的CRuntimeClass----可能仅在DECLARE_DYNAMIC中.如果这样的CRuntimeClass对象的定义和该类的其它实现代码在同一个文件,对象中的数据(如消息映射表)指向这个类中的函数,最终会将所有这样的函数的放入OBJ文件,不管它们有没有被用户引用----它们只被一些不被用户引用的数据所引用.但因它们所在的comdat有用户实际引用到的函数,不会被削减,结果产生大量不必要的代码.在CView的例子中,CFrameWnd需要使用了RUNTIME_CLASS(CView),因此使用CFrameWnd的代码都需要CRuntimeClass对象,如果视图类的CRuntimeClass对象的定义放在视图类的主实现文件ViewCore.cpp中,则仅使用CFrameWnd的程序就会因包含视图类的函数而变得更大.
微软的解决方案是取用精心设计的示例,在链接后检查生成的MAP文件确定是否有不必要的内容加入进去,据此进行代码实现位置的交换调整数,它们仅做了少量的变动,对库粒度却有了很大的改进.主要参考了<MFC Internals>,George Shepherd,Scot Wingo,这本书的其它部分也相当精彩,不过它引用MFC的好象是4.2以前的版本,有些内容已经和当前版本不符了.
记得我当时分析MFC的Dock/Float特性,绕了好多弯路,把MFC这部分源码看完了,才得到这本书,可惜它里面讲的对我而言已经没有价值了,用楼主的话,就是“闭着眼睛也能知道”了,不过如果一开始就看这本书的话,会省力不少,所以还是建议大家常备,呵呵。