接觸VC之二:MFC類基礎,C++程序編寫規范介紹
作者:釋雪
由於本文是面對C語言基礎的(因為我就是從C學起來的),而MFC是利用C++類技術構建起來的。因此有必要在此為只了解C的朋友們,普及一下C++語言中類的概念。熟悉C++的朋友可以跳過本部分。 從總體來說C++是向下兼容C的,你可以很不費力氣地將用C編好了的程序拿到C++環境下編譯執行。其C++只不過是在C的基礎上添加面向對象技術(OOP),也就是類的概念,且值得一提的是C與C++都是由美國的貝爾實驗室(在之前我只知道發明過電話)發明的。
一、什麼是類?
按一些書本上的定義來說“就是一種復雜的數據類型,它是將不同類型的數據和與這些數據相關的操作封裝在一起的集合體。因此,類中的數據具有隱藏性,類還具有封裝性。”嗯,類還像上面的那句話一樣,具有很強的抽象性。讓我來用一個例子來解釋類吧。 嗯,我們世界上有一個生物種類叫做鳥,在C++上世界我們也可以制作一個類叫做鳥類。它應該有頭,有軀干,有腿,有內髒,還有一個非常重要的翅膀。於是,其類描述如下:
class Aves{ char m_strHead[10]; char m_strTrunk[10]; char m_strCrura[10]; char m_strWing[10]; char m_strBowels[10];};哈,這樣一個鳥類建立好了,怎麼樣與C中結構體沒什麼兩樣吧。(在C++中struct與class基本上是同義詞,過一會兒會說到它們有什麼不同的。)如果你想建立一個小鳥的話,不用像C中那樣麻煩地打struct Aves XXX,而是直接使用Aves XXX就可以了,不打前面的struct或class。在人類對鳥類形成概念之前,鳥的翅膀、軀體等等就真的存在了(沒有人有疑議吧?),但在人們根本不知道鳥的那對長滿羽毛的撲扇撲扇就可以飛的東西叫什麼名字,也不會知道翅膀這個詞指的是什麼意思。現在我們的這個C++鳥類也正處於這個狀態,在那些成員變量中沒有被賦與任何值。而現實生活中,一個種類中的具體名字是在一個類對象形成初期被命名的,這是一個名詞初始化的過程。在C++類中,當建立一個類對象時總也要有一個初始化各成員變量的過程,於是構造函數被引入了。它在一個實例被聲明和被建立(這兩個有一些區別)時調用。我們的C++鳥類各個成員變量的賦值命名就可以利用它來實現:
class Aves{ Aves () { strcpy(m_strHead, "Head"); strcpy(m_strTrunk, "Trunk"); strcpy(m_strCrura, "Crura"); strcpy(m_strWing, "Wing"); strcpy(m_strBowels,”Bowels”); } char m_strHead[10]; char m_strTrunk[10]; char m_strCrura[10]; char m_strWing[10];};瞧,我是怎麼在類裡面建立一個構造函數的。一個類的構造函數的名字要與其類名同名,且不能有返回值,void也不行。我們在構造函數中,對各個成員函數命名。當Aves bird;時(聲明一個bird對象),Aves類的構造函數將會被調用,把bird.m_strHead,bird.m_strTrunk等等成員變量分別賦值為”Head”,”Trunk”。這樣一講,希望大家對構造函數有了一定的了解了。我們既然有構造函數可以對類成員進行初始化,那麼用什麼來對類成員銷注呢?說白了就是有在建立類對象時調用的函數,什麼函數是在類對象被刪除時調用的函數呢?那就是析構函數,其命名規則與構造函數是一樣的,只不過需要在其函數名前緊加一個~(波浪號),且不能有參數。如我們的類就是~Aves();至於析構函數具體作用嘛…舉個例子來說,當在構造函數中申請了一段內存,我們就必須在析構函數中釋放這段內存,否則會內存洩漏。那麼什麼時候會引發聲明的類對象被刪除呢?要解決這個問題,我還需要借用一個叫名域(name space)的概念。當系統執行指針離開聲明的類對象所在名域時,就會引發類對象的刪除(類型的有效型也可以如此解釋)。而名域這個概念最實稱的理解就是一對大括號,在這對括號內的空間就是一個名域。(當然名域其實不是這麼簡單的。如類本身就是一個名域,還可以自己設定一個名域,用於類型聲明設定,可以用已有的類型沖突。名域真實用途是這個。具體含義參見《C++標准庫》,圖書大廈有侯捷先生的譯本)比如:
{//名域1 char * strValue; {//名域2 Aves bird; {//名域3 strValue=bird.m_strWing; }}//<<就在後大括號這裡引發了bird對象的析構函數strValue=”Blue Atlantis”;}這裡有3個名域,我在名域2中聲明了一只小鳥。因為名域3也被包括在名域2裡,所以名域3中的空間也屬於名域2,於是在名域3中引用小鳥對象是正確的。當執行指針離開名域2那一瞬,C++系統將會把在名域2中聲明的所有變量及對象刪除掉。當對象被刪除時,首先會執行析構函數,然後系統再去釋放對象所占用的內存空間。所以當執行到strValue="Blue Atlantis";這一句時,這只小鳥就已經不存在,再去引用它就會編譯錯誤。另外,要講一講對象的建立。一種是像變量一樣聲明建立起來對象,像上面的Aves bird;另一種就是用new語句來建立起來對象。如:
Aves *bird;bird= new Aves();new語句跟著一個類的構造函數,它會在內存建立起來一個對象,並把這個對象的指針返回出來。這樣建立起來的對象沒有名域空間的限制。如果要將這個對象刪除掉必須手動的使用delete語句。如:
delete bird;delete後面跟著指向要刪除對象的指針變量。注意,這個指針變量的類型直接影響到對象的刪除時所使用的析構函數。所以,什麼類型的對象,就要用什麼類型的指針來指向刪除。真實的鳥類應該是可以飛翔(絕大部分),可以發出叫聲,可以在陸上跑(至少可以跳)。所以我們也應該讓我們的鳥類也可以跳,可以飛吧。於是,我要向類中添加成員函數。聲明成員函數可以有兩種方法,一種是在類的聲明體裡面,像上面例子中構造函數的聲明方法,另一種是在類的聲明體外面。外部的表現寫法為 返回值 類名::函數名(參數列表)。注意::是由於兩冒號組成。下面的代碼就是使用第二種聲明方法(當然,兩種方法可以混用):
#include <iostream.h>#include <string.h>class Aves{ public: Aves (); ~Aves (); void tweet(); void run(); void fly(); char m_strHead[10]; char m_strTrunk[10]; char m_strCrura[10]; char m_strWing[10];private: char m_strBowels[10];};Aves::Aves(){ strcpy(m_strHead, "Head"); strcpy(m_strTrunk, "Trunk"); strcpy(m_strCrura, "Crura"); strcpy(m_strWing, "Wing"); strcpy(m_strBowels, "Bowels"); cout<<"a bird born!"<<endl;}Aves::~Aves(){ cout<<"a bird die!"<<endl;}void Aves::tweet(){ cout<<"jijijijijijiji"<<endl;}void Aves::run(){ cout<<"I can run by "<<m_strCrura<<endl;}void Aves::fly(){ cout<<"I can fly by "<<m_strWing<<endl;}void main(){ Aves bird; bird.fly(); bird.run();}我們可以在主函數的運行下看到整個類的運作。在聲明時,一只小鳥誕生,構造函數被運行,輸出”a bird born”。當對象被刪除時,析構函數被執行,輸出”a bird die”。請注意,在類聲明體中,我添加了public:和private:這樣的語句。這是設定訪問權限的語句,它是將從它這一行起直到下一個訪問權限語句前的所有成員變量和成員函數設置成它指定的權限。如public則設置成公有權限,設置這種權限的成員可以被外部所使用,private則設置私有權限,設置成這種權限的成員是不可以被外部所使用,只能夠在其成員函數內被使用,如:使用bird. m_strBowels是非法的,因為其是私有成員變量。因為鳥的內髒在外部是看不見的,它只能被鳥本身所使用。前面說過,在C++中struct和class基本上是同義詞。在class中如果一開始沒有指定權限關鍵字,那麼默認權限為private,而在struct中默認權限是public。當成員函數需要使用其它成員時,可以直接寫其名稱,如在run()函數中直接使用其成員變量m_strCrura。在實際上,完全的寫法應該是this->XXX成員。this是一個本類的指針,在這個類中就是Aves*。它代表當前實例對象的指針,在bird對象中應用run()時,this就是&bird。可以將run函數改寫為
void Aves::run(){ cout<<"I can run by "<<this->m_strCrura<<endl;}講了這麼多,相信大家應該可以寫一個自己的類了吧?快用你的VC,建立一個Win32 Console Application工程,用新建Files向工程添加一個C++ Source file文件,來試試寫一個自己的C++程序吧。