微軟基礎類庫MFC(Microsoft Foundation Classes),是一個微軟公司提供的類庫(class libraries),以C++類的形式封裝了Windows的API,并且包含一個應用程式架構,以減少應用程式開發人員的工作量。其中包含的類包含大量Windows句柄封裝類和很多Windows的内建控件群組件的封裝類。
初學者常誤認為VC++開發必須使用MFC。這種想法是錯誤的。作為Application Framework,MFC的使用隻能提高某些情況下的開發效率,隻起到輔助作用,而不能替代整個Win32 程式設計。
Application Framework
基本上你可以說,Application Framework是一個完整的程式模型,具備标準應用軟體所需的一切基本功能,像是檔案存取、列印預視、資料交換...,以及這些功能的使用接口(工具欄、狀态列、菜單、對話框)。
Windows 應用程式中,MFC 的主包含檔案為"Afxwin.h"。
MFC實際上是微軟提供的,用于在C++環境下編寫應用程式的一個架構和引擎,VC++是Windows下開發人員使用的專業C++ SDK(專業軟體開發平台)(SDK,Standard SoftWare Develop Kit),MFC就是挂在它之上的一個輔助軟體開發包,MFC作為與VC++血肉相連的部分(注意C++和VC++的差別:C++是一種程式設計語言,是一種大家都承認的軟體編制的通用規範,而VC++隻是一個編譯器,或者說是一種編譯器+源程式編輯器的IDE
MFC是Win API與C++的結合,API,即微軟提供的Windows下應用程式的程式設計語言接口,是一種軟體程式設計的規範,但不是一種程式開發語言本身,可以允許使用者使用各種各樣的第三方(如我是一方,微軟是一方,Borland就是第三方)的程式設計語言來進行對Windows下應用程式的開發,使這些被開發出來的應用程式能在Windows下運作,比如VB,VC++,Java,Delhpi程式設計語言函數本質上全部源于API
最後要明白MFC不隻是一個功能單純的界面開發系統,它提供的類絕大部分用來進行界面開發,關聯一個視窗的動作,但它提供的類中有好多類不與一個視窗關聯,即類的作用不是一個界面類,不實作對一個視窗對象的控制(如建立,銷毀),而是一些在Windows(用MFC編寫的程式絕大部分都在Windows中運作)中實作内部處理的類,如資料庫的管理類等,學習中最應花費時間的是消息和裝置環境,對C++和MFC的學習中最難的部分是指針,C++面向對象程式設計的其它部分,如資料類型,流程控制都不難,建議學習資料結構C++版。
MFC是面向對象程式設計與Application framework的完美結合,他将傳統的API進行了分類封裝,并且為你建立了程式的一般架構
2012.6
C++ 類和類的定義
類:
它是将不同類型的資料和與這些資料相關的操作封裝在一起的集合體。(參數和函數)
這有點像C語言中的結構,唯一不同的就是結構沒有定義所說的“資料相關的操作”,“資料相關的操作”就是我們平常經常看到的“方法”。
類的定義格式 (和結構體類似)
class <類名>
{
public:
<成員函數或資料成員的說明>
private:
<資料成員或成員函數的說明>
};
<各個成員函數的實作>
下面給出一個日期類定義的例子:
class TDate
void SetDate(int y, int m, int d);
int IsLeapYear();
void Print();
int year, month, day;
//類的實作部分
void TDate::SetDate(int y, int m, int d)
year = y;
month = m;
day = d;
}
int TDate::IsLeapYear()
void TDate::Print();
cout<
這裡出現的作用域運算符::是用來辨別某個成員函數是屬于哪個類的。
該類的定義還可以如下所示:
void SetDate(int y, int m, int d)
{year=y; month=m; day=d;}
int IsLeapYear()
void Print()
{cout<
int yeay, month, day;
這樣對成員函數的實作(即函數的定義)都寫在了類體内,是以類的實作部分被省略了。如果成員函數定義在類體外,則在函數頭的前面要加上該函數所屬類的辨別,這時使用作用域運算符::。(和結構體類似)
4、經常習慣地将類定義的說明部分或者整個定義部分(包含實作部分)放到一個頭檔案中。
在類的聲明和成員函數的實作(即函數的定義)分開寫時,在類的聲明部分中,不用寫出變量名,隻要聲明參數的類型即可.
通常将成員函數寫在前面,資料成員寫在後面.
析構函數 ~stud( )
如果構造函數打開了一個檔案,最後不需要使用時檔案就要被關閉。析構函數允許類自動完成類似清理工作,不必調用其他成員函數。
析構函數也是特殊的類成員函數。簡單來說,析構函數與構造函數的作用正好相反,它用來完成對象被删除前的一些清理工作,也就是專門的掃尾工作。
當你用“new”操作符為變量或指針動态配置設定記憶體時,它們所占用的記憶體不會随着你的程式的關閉而關閉,這時就需要用到析構函數來把你的變量或指針銷毀,以騰出它們所占用的記憶體空間~~~~
以C++語言為例,析構函數名也應與類名相同,隻是在函數名前面加一個波浪符~,例如~stud( ),以差別于構造函數。它不能帶任何參數,也沒有傳回值(包括void類型)。隻能有一個析構函數,不能重載。如果使用者沒有編寫析構函數,編譯系統會自動生成一個預設的析構函數,它也不進行任何操作。是以許多簡單的類中沒有用顯式的析構函數。
也就是說在包含該對象的函數的末尾就會調用析構函數
局部的對象 在該對象聲明的函數末尾被釋放...
你可以看下作用域的定義..析構函數就是在對象的作用域的末尾釋放
為了不誤導人...我還是舉個例子..
如果是
class A
....
void f()
A a;
//這種情況a的作用域就是整個函數 在f末尾釋放
for(A a;a.yes();a++)//這裡聲明的是一個計數器a..(這種情況一般是疊代器)..
{
...
}
//這裡是a作用域結束的時候 調用析構函數
A* p=new A;
delete p;//A作用域結束 調用析構
如果A是全局對象..那麼就在程式末尾釋放
顯式的調用很少見..我就不舉例了..
VC
1、C++中 "cannot open Debug/*.exe for writing"
第一次編譯運作後,你沒有關掉那個程式,是以更改後再次編譯就提示不能寫入。
記得編譯前關閉程式,或者到任務管理器的看看程序是否存在,有的話結束掉。
那麼打開任務管理器看看那個程序在不在,可能你關了視窗,但程式還沒有結束
2012.7.22
cout<<"Hello,World!"<<"Flush the screen now!!!"<<flush;
這樣當程式執行到operator<<(flush)之前,有可能前面的字元串資料還在緩沖區中而不是顯示在螢幕上,但執行operator<<(flush)之後,程式會強制把緩沖區的資料全部搬運到輸出裝置并将其清空。而操縱符endl相當于<<"\n"<<flush; ( 換行,重新整理緩沖)
2012.8.14
GDI
GDI是Graphics Device Interface的縮寫,含義是圖形裝置接口,它的主要任務是負責系統與繪圖程式之間的資訊交換,處理所有Windows程式的圖形輸出。
pDC指向的是你從堆上申請的記憶體塊
也就是GDI對象.就是常說的裝置上下文.他其實是個結構體
用來儲存需要處理的對象的一些屬性
pDC看你的聲明是怎麼處理的
有時候在函數中當參數,接受的是你的參數的位址
有時候你需要繪圖的時候用
CDC *pDC;
pDC=new CDC;
或者pDC->CreateCompatibleDC();
或者pDC->m_hDC=::GetDC();
等..
他本身就是一個CDC對象
他包含一個HDC的對象!也就是CDC的核心
DC是MFC的DC的一個類
HDC是DC的句柄,API中的一個類似指針的資料類型.
MFC類的字首都是C開頭的
H開頭的大多數是句柄
這是為了助記,是程式設計讀\寫代碼的好的習慣.
CDC中所有MFC的DC的基類.常用的CClientDC dc(this);就是CDC的子類(或稱派生類).
CDC等裝置上下分類,都含有一個類的成員變量:m_nHdc;即HDC類型的句柄.
記住下面的一句話,會有助于你的了解.
MFC的類,是在用window API語句開發出來的有一定功能的小程式.(也可稱為類).使用它的預設方法,就是,記住它的名字與參數(可以用筆記,代替腦記).
如果将window api比做彙編語言
那麼MFC就相當于Basic語言.
2012.8.24 基類私有成員的通路權
C++ 基類私有成員被子類繼承嗎2011-6-9 15:23提問者: 623669584 | 浏覽次數:1031次
C++ 基類私有成員被子類繼承嗎,子類繼承了基類的私有成員 但不能被通路嗎?
還 是 不能繼承基類的私有成員 也不能通路基類的私有成員???
我來幫他解答
2011-6-9 15:42滿意回答
你好,總的來說,基類的所有成員被派生類繼承後都變成派生類所擁有了,隻是對于繼承而來的private成員沒辦法直接通路而已,這樣設計保證了基類private成員的安全性。如果你希望基類的某些成員被派生類繼承且能通路而又不允許外界普通使用者代碼通路的話,将基類的那些成員聲明為protected就好了。
C++ Primer裡面關于通路控制和繼承是這麼說的
“
在基類中,
public和private标号
具有普通含義:使用者代碼可以通路類的public成員而不能通路private成員,private成員隻能由基類的成員和友元通路。
派生類對基類的public和private成員的通路權限于程式中任意其他部分一樣:它可以通路public成員而不能通路private成員。
protected标号
可以被派生類對象通路但是不能被該類型的普通使用者通路。
”
順便提一下,對于protected成員還蠻特别的:“派生類隻能通過派生類對象通路其基類的protected成員,派生類對其基類類型對象的protected成員沒有特殊通路權限”
2012.8.24
消息函數OnLButtonDown和OnLButtonUp中最後一句CView::OnLButtonDown(nFlags, point)的作用
暫且可信的回複:
如果你注釋了CView::OnLButtonDown(nFlags, point); 後果就是當有WM_LBUTTONDOWN消息的時候它隻會執行MessageBox("View Clicked!"); 而系統一些預設下的LBUTTONDOWN操作不會被執行,如果你了解switch語句的話,應該知道它有個default,CView::OnLButtonDown(nFlags, point);和default性質一樣,它把你處理過的WM_LBUTTONDOWN消息傳遞給那些還能處理這樣消息的處理函數
<a href="http://zhidao.baidu.com/question/393611846.html">http://zhidao.baidu.com/question/393611846.html</a>
其他回複:
CDrawDemoView類是從CView繼承類,在CView的派生類CDrawDemoView中使用過(UINT nFlags, CPoint point)等參數後,系統要将他們傳回基類,如果你改變參數的内容 基類将無法得到這些參數,對這個函數沒影響是由于你沒調用他的基類函數,如果你調用基類函數并且使用這兩個傳回的參數,就有可能錯誤。是以這個函數盡量不要改變參數的值,但是可以使用.
<a href="http://zhidao.baidu.com/question/109794460">http://zhidao.baidu.com/question/109794460</a>
CView中原本就實作了滑鼠左鍵處理功能:OnLButtonDown
而CMyView繼承自CView,進而CMyView即使不覆寫定義
OnLButtonDown函數,也可以直接使用CView的OnLButtonDown函數。
CMyView之是以覆寫定義(override) OnLButtonDown函數,是因為繼承來
的版本功能不滿足要求。
CMyView類在重新實作OnLButtonDown函數時發現,隻要先做一些預
處理(以下幾行就是預處理),
CMyDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
pDoc->m_pointMouse=point;
Invalidate();
後面就完全可以按照原來的方式處理了,是以直接調用基類
的OnLButtonDown函數版本:
CView::OnLButtonDown(nFlags,point);
注意類名字首,而不是:
OnLButtonDown(nFlags,point);
//這個将調用CMyView::OnLButtonDown(nFlags,point);
//這變成了遞歸調用,遞歸若沒有退出條件将導緻堆棧溢出錯誤
<a href="http://tieba.baidu.com/f?kz=293822983">http://tieba.baidu.com/f?kz=293822983</a>
有趣的答複:
說白了就是把消息傳回去給老總,簡單分析說明就是有一個客戶想要告訴你們公司一個消息,但這個消息先讓你知道了,你可以在把消息傳達到老總那時之前做一些手腳,做成手腳之後再把消息傳給老總。你所說的最後那行代碼就是傳回給老總的意思。
<a href="http://www.vczx.com/forum/showthread.php?s=799ee5a93656a30d81f6962be6beab0b&threadid=15033">http://www.vczx.com/forum/showthread.php?s=799ee5a93656a30d81f6962be6beab0b&threadid=15033</a>
DoDataExchange() 2012.8.24
對話框的構造函數裡面初始化一個變量,再用DoDataExchange函數将它綁定到你的動态按扭中,比如:
DDX_Check(pDX, IDC_CHECK1, m_Lesson1);這就是将m_Lesson1(這是一個外部變量,其定義在對話框的構造函數裡)綁定到IDC_CHECK1中。
看下DDX_Check函數原型:void AFXAPI DDX_Check(CDataExchange* pDX, int nIDC, int& value);可以看到m_Lesson并不是真的添加到IDC_CHECK1控件裡了,注意這是int& value,隻是一個值引用而已。差不多的意思就是這個變量被架構傳遞給控
DoDataExchange永遠不被直接調用,它隻是呼叫UpdateData函數時才會被調用。(因為每更新一次,它都需要重新綁定一次。是這樣子嗎?)
UpdataData函數内部調用了DoDataExchange。該函數隻有一個布爾型參數,它決定了資料傳送的方向。
UpdateData(false)是将變量的值傳到控件.
UpdateData(TRUE)是從控件中取值到關聯的變量
void CDlgSelectCS::DoDataExchange(CDataExchange* pDX)
CDialog::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT_SCR, m_ScrCS_Name);
DDX_Text(pDX, IDC_EDIT_DEST, m_DestCS_Nam);
DoDataExchange會被架構調用,用來改變和驗證對話框的資料。在這個函數中一般是将控件和某些變量關聯,當在其它地方改變量的值,通過UpdateData 進行雙向交換。如:
UpdateData();//将控件的值傳給變量
m_ScrCS_Name = "Xian 1980.prj";//分别為控件的變量指派
UpateData(FALSE);//将變量的值傳給控件
VS利用向導添加數組 2012.8.27
添加數組:
類型自己寫 如建立8個元素的數組:float [8]
名字是:angle
添加指針數組:
類型自己寫 如建立8個元素的數組:float * [8]
控件變量 添加變量 2012.8.27
MFC中關聯一個控件和變量的時候,可以選擇是控件方式還是值方式,如果是控件方式,那麼就是這個變量就代表了控件,如果是值方式,那麼這個變量就代表了控件中顯示的值。比如你說的靜态控件,可以與CStatic類型的變量關聯,也可以與CString類型的關聯。其實所謂的關聯,隻是MFC的一層封裝而已,内部還是采用Windows SDK來操作的。你如果想深入了解的話,可以去看看Windows SDK開發方面的東西,或者也可以深入到MFC的源代碼中看看,MFC源代碼在安裝時有選項。
消息映射機制 消息映射表 2012.8.29
BEGIN_MESSAGE_MAP(CCH372_CPlusDlg, CDialog)
這樣就是一個工程叫CCH372_CPlusDlg的消息映射表,它以BEGIN_MESSAGE_MAP開始
<a href="http://baike.baidu.com/view/3517678.htm">http://baike.baidu.com/view/3517678.htm</a>
2012.9.1 CWnd CDC
CWnd 是視窗類
CDC 是裝置描述類
CWnd 是封裝了所有對視窗操作的類
CDC 是封裝了所有對繪圖操作的類
CWnd 封裝了一系列視窗的操作的API,如視窗移動,視窗建立銷毀顯示,子父視窗關聯等等
CDC 則是繪圖用的,如繪個線了,繪個矩形了,繪個其它字型了,繪個Bitmap了什麼的
2012.9.5 顯示最近打開檔案 LoadStdProfileSettings();
最近檔案清單可以讓你很友善地打開你以前曾經打開過的檔案,那麼,如何為自己的應用程式加入最近檔案清單功能呢?最簡單的方法就是在你建立工程的時候選擇包含最近檔案清單功能,也就是在 MFC AppWizard 的第 4 步的時候使 “How many files would you like on your recent file list?” 的值不為 0 即可。
1、顯示最近檔案
如果你在建立工程的時候沒有選擇包含最近檔案清單功能,那麼可以按照如下的方法為你的工程加入它:
1.在你的“檔案”菜單中添加一個名稱為“最近檔案”的菜單項,其 ID 為 ID_FILE_MRU_FILE1。
2.在你的工程的 App 類的 InitInstance 方法中将
LoadStdProfileSettings(0);
改成:
LoadStdProfileSettings();
即可。
最近檔案清單項是儲存在系統資料庫中,以你的工程名為主鍵的字元串值中,可以用SetRegistryKey(_T("skyice software"));改成你需要的名稱:skyice software。
(
這樣,你的工程就有了最近檔案清單功能。事實上,以這種方法生成的最近檔案清單項是儲存在系統資料庫中HKEY_CURRENT_USER\Sofrware\Loacl Appwizard-Generated Applications 下,以你的工程名為主鍵的, Recent File List 主鍵中 File? 格式的,字元串值中。LoadStdProfileSettings 的參數值決定了儲存在這裡的最近檔案的數目,其預設值(沒有參數時)為 4。 Loacl Appwizard-Generated Applications 主鍵是Visual C++ 預設的,在工程的 App 類的 InitInstance 方法中由 SetRegistryKey() 函數建立的,你可以将其改成你需要的名稱,例如:SetRegistryKey(_T("skyice software"));
)
那麼,如何處理從菜單中選擇的最近檔案清單中的檔案呢?由于在菜單中隻有 ID_FILE_MRU_FILE1 這一個菜單項,其餘的菜單項都是由 LoadStdProfileSettings(); 動态的加上的,是以,用一般的方法難以實作對菜單項的響應。此時,可以采用如下的方法:
2、打開選擇的檔案
1.在 CMainFrame 類中加入對菜單項 ID_FILE_MRU_FILE1的響應。
2.在 MainFrm.cpp 中将
ON_COMMAND(ID_FILE_MRU_FILE1,OnFileMruFile1)
改成
ON_COMMAND_RANGE(ID_FILE_MRU_FILE1,ID_FILE_MRU_FILE4, OnFileMruFile1)
即可。
以後,所有對最近檔案清單中檔案的選擇都由 CMainFrame 方法 OnFileMruFile1 響應,你可以在此函數中判斷具體是選擇了哪個檔案,進而做出相應的處理。
轉自:http://hi.baidu.com/haoyan1983/blog/item/01821f000bb38f1a7aec2c68.html
2012.9.6
GetHeadPosition() 和GetNext()
etHeadPosition 傳回的是連結清單頭元素的位置
GetNext(pos) 傳回的是連标中pos所指的元素并将pos指向下一個元素
調用GetNext後pos的值就改變了
可以用一下循環周遊連結清單所有元素
for (POSITION pos = list.GetHeadPosition(); pos != NULL;)
{
(yourclass*) yc = (yourclass*)GetNext(pos);
MSDN中:
C++
CObList list;
POSITION pos;
list.AddHead(new CAge(21));
list.AddHead(new CAge(40)); // List now contains (40, 21).
// Iterate through the list in head-to-tail order.
#ifdef _DEBUG
for (pos = list.GetHeadPosition(); pos != NULL;)
{
afxDump << list.GetNext(pos) << _T("\n");
}
#endif
The results from this program are as follows