孫鑫 VC++深入詳解——學習筆記
阿新 • • 發佈:2019-01-17
第1課
Windows程式內部執行機制
1.MFC生成的C++原始檔中都有StdAfx.h,此檔案包含了常用的AFX函式的宣告,其中有afxwin.h,此檔案包含了CRECT,CPoint,CWnd等許多類及其方法的宣告。
2.Project->Setting->Debug可以加入命令列引數。
3.在SDK中要加入"windows.h"和stdio.h。因為LoadCursor,MessageBox等函式的宣告在這個檔案中。
4.建立一個完整的視窗的四個步驟SDK,1設計視窗類,2註冊視窗類,3建立視窗,4顯示視窗
5.函式名可以代表函式程式碼的首地址,即可作為函式指標。
6.要檢視VC資料型別,可以在MSDN中輸入“BOOL”然後選擇“DATA
TYPE”。
7.atof將字串轉化為float,atoi將字串轉化為int型。
8.所有從CWnd類派生的類都有m_hWnd控制代碼。
9.變數的生命週期:可以認為出了包含它的大括號,這個變數的生命週期結束。所以全域性變數的宣告位於所有大括號之外。但是用new宣告的變數和用static宣告的變數除外。
10.SDK示範程式,見下面。
11.sprintf格式化字元,其標頭檔案為stdio.h,在MFC中格式化字元用CString.Format
12.GetDC()與ReleaseDC()要成對使用,否則會記憶體洩漏。同樣, BeginPaint()與EndPaint()。
13.GetStockObject()得到畫筆、畫刷、字型、調色盤的控制代碼,使用時必須用型別轉換。
14.什麼時候用NULL,什麼時候用0.答,對指標賦值時用NULL,對變數賦值時用0.
15.什麼是野指標?答:將指標指向的變數的記憶體釋放後,此指標即變成野指標!如何避免野指標?答:將此指標指向NULL即可。p=NULL;
16.SDK程式碼流程:
#include "windows.h"//包含標頭檔案LoadCursor,TextOut等函式
#include "stdio.h"//包含sprintf,printf等函式
LRESULT CALLBACK MyProc(...);// 宣告回撥函式
int WINAPI WinMain()
{
WNDCLASS wndcls;//設計視窗類
wndcls.hcursor=LoadCursor();//初始化
....
RegisterClass(&wndcls);//註冊視窗類
hwnd=CreateWindow(...);//建立視窗
ShowWindow(..);//顯示視窗
UpdateWindow(..);
MSG msg;//定義訊息結構體
while(GetMessage(...))//訊息迴圈
{
...
}
return 0;
}
LRESULT CALLBACK MyProc(...)//實現回撥函式
{
switch(uMsg)
{
case WM_CHAR:
break;
...
}
}
第2課 掌握C++
1.定義結構體和類時別忘記在最後加入";"號!例如Class Point{int x;int y;}; 2.#include <xxx.h>與#include "xxx.h"的區別:<>不查詢執行時目錄,""查詢執行時目錄! 3.類的定義中,如果未指明成員型別,則預設為private.而結構體中則預設為public. 4.引用:引用經常用在函式的傳參上。另外數值交換函式也經常用引用。例 change(int &x,int &y){int temp;temp=x;x=y;y=x}呼叫時即可以用int a=3;int b=4;change(a,b);一般不用指標來作為引數進行數值交換。因為會引起歧義。 5.通常將類的定義放.h檔案,而將其實現放在cpp檔案中,別忘記了在cpp檔案中#include "xxx.h" 6.如何防止類的重複定義? 用#inndef Point_H_H #define Point_H_H class Point{}; #endif來防止 7.原始檔cpp檔案單獨編譯成obj檔案。最後由連結器將與將要使用到的C++標準庫類連結成exe檔案,標頭檔案不參加編譯。所以在cpp檔案中別忘記了加入#include "xxx.h" 8.函式的覆蓋,在子類中重寫父類的函式,此時採用早期繫結的方法。如果加入了virtual,則將採用遲繫結的技術,在執行時根據物件的型別確定呼叫哪一個函式。此遲繫結技術是MFC的類的繼承的精髓。 9.強制型別轉換。如果CFish從CAnimal派生而來。則可以將魚的物件轉換為CAnimal的物件,而反之則不行。從現實中理解也是正常的,魚可以是動物,而動物卻不是魚。再如int可以強制轉換成char型。而反之則出錯。 10包含標頭檔案時,<>和””是不同的。<>表示編譯器從系統目錄下開始搜尋,然後再搜尋PATH環境變數所列出的目錄,不搜尋當前目錄,找不到就出錯。而””則表示先從當前目錄搜尋,然後才是系統目錄和PATH環境變數列出的目錄。所以,如果標頭檔案在系統目錄下,就用<>,如果標頭檔案在當前目錄下,就用””,這樣可以加快搜索速度。 11在類的標頭檔案(*.h)的開頭,一般定義有如下巨集: #ifndef ANIMAL_H_H #define ANIMAL_H_H Class *** …… #endif 這麼做就是為了避免類重複定義。第3課 MFC框架程式
1.在main或WinMain之前,全域性變數(物件)已經被分配記憶體並初始化了。 2.在MFC中在WinMain之前有個theApp全域性變數先被構造並被初始化,而由於子類建構函式執行前,其父類的建構函式先被執行,所以CTestApp的父類CWinAPP的建構函式先執行。產生了theApp物件後,在WinMain()中的指標*pThread和*pApp就有了內容。 知識點:Afx字首的函式代表應用程式框架(Application Framework)函式,都是全域性函式,在程式的任何地方都可以呼叫它。 3.MFC大致流程: CTestApp theApp;//構造全域性物件 WinMain() { AfxWinMain();//呼叫下面的函式 } AfxWinMain() { pThread->Initinstance();//初始化工作和註冊視窗類,視窗顯示和更新 pThread->Run();//訊息迴圈 } 而在BOOL CTestApp::InitInstance()中的程式碼 CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CTestDoc), RUNTIME_CLASS(CMainFrame), // main SDI frame window RUNTIME_CLASS(CTestView)); AddDocTemplate(pDocTemplate); 完成了將這三個類關聯起來的工作。 4.如何在單文件檔案中顯示一個CButton的物件? 在CMainFrame::OnCreate()中定義一個CButton的物件btn;然後呼叫btn.Create("維新",WS_DISABLED |WS_CHILD | WS_VISIBLE | BS_AUTO3STATE, CRect(0,0,300,100),/*GetParent(),*/this,123); 注意點: (1).此處btn不能是區域性變數,否則它的生命週期太短,將不能顯示。 (2).在create函式的第二個引數中加入WS_VISIBLE引數才行。否則必須呼叫ShowWindow 也可以在view的OnCreate訊息響應函式中加入 (3).CButton類的定義標頭檔案在afxwin.h中,而stdafx.h包含了afxwin.h,所以可以直接使用。因為MFC中的每一個類中都有#include "stdafx.h"的宣告。 5一個單文件視窗(多文件),標題欄和選單欄位於MainFrame的非客戶區,而工具欄位於MainFrame的客戶區。而檢視位於MainFrame的客戶區。第4課 簡單繪圖
1.在單文件中view擋在MainFrame的前面(View-牆紙,MainFrame-牆)。此時如果編寫針對MainFrame的mouseClick事件,將不會有反應。 2.訊息響應會在3處修改程式碼, (1)在標頭檔案中, //{{AFX_MSG(CDrawView) afx_msg void OnLButtonDown(UINT nFlags, CPoint point); //}}AFX_MSG DECLARE_MESSAGE_MAP() (2)cpp檔案的begin MessageMap和End MessageMap之間, BEGIN_MESSAGE_MAP(CDrawView, CView) //{{AFX_MSG_MAP(CDrawView) ON_WM_LBUTTONDOWN() //}}AFX_MSG_MAP END_MESSAGE_MAP() (3)最後是要有函式實現的程式碼。 void CDrawView::OnLButtonDown(UINT nFlags, CPoint point) { // TOD Add your message handler code here and/or call default m_ptOrigin=m_ptOld=point; m_bDraw=TRUE; CView::OnLButtonDown(nFlags, point); } 3.畫線:定義一個成員變數儲存mouseDown的點m_Point 1)API函式方法畫線用HDC 2)用CDC類成員函式畫線。此時別忘記ReleaseDC 3)用CClientDC 4)用CWindowDC,用它甚至可以整個螢幕區域畫線。 下面是上面4種方法的程式碼 (1) /*HDC hdc; hdc=::GetDC(m_hWnd); MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,NULL); LineTo(hdc,point.x,point.y); ::ReleaseDC(m_hWnd,hdc);必須成對使用。*/ (2) /*CDC *pDC=GetDC(); pDC->MoveTo(m_ptOrigin); pDC->LineTo(point); ReleaseDC(pDC);必須成對使用。*/ (3) //CClientDC dc(this); /*CClientDC dc(GetParent()); dc.MoveTo(m_ptOrigin); dc.LineTo(point);此處不需要ReleaseDC,因為CClientDC會自動釋放DC*/ (4) //CWindowDC dc(this); //CWindowDC dc(GetParent()); /*CWindowDC dc(GetDesktopWindow());//此時可以在整個螢幕上畫線。 dc.MoveTo(m_ptOrigin); dc.LineTo(point);*/ /*CPen pen(PS_DOT,1,RGB(0,255,0)); CClientDC dc(this); CPen *pOldPen=dc.SelectObject(&pen); dc.MoveTo(m_ptOrigin); dc.LineTo(point); dc.SelectObject(pOldPen);*/ 5)用Bitmap填充所畫的矩形。 CBitmap bitmap; bitmap.LoadBitmap(IDB_BITMAP1); CBrush brush(&bitmap); CClientDC dc(this); dc.FillRect(CRect(m_ptOrigin,point),&brush); //CBRUSH::FromHandle是靜態成員函式,所以可以用下面的方法呼叫。 CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));//NULL_BRUSH表示透明畫刷,畫出來的圖形的背景就是透明的 CBrush *pOldBrush=dc.SelectObject(pBrush); dc.Rectangle(CRect(m_ptOrigin,point)); dc.SelectObject(pOldBrush); m_bDraw=FALSE; 6)用