用MFC製作的工程由很多檔案構成,它不能象一般C++程式那樣隨意在類外定義全域變數,在這裡要想定義能被工程內多個檔案分享權限設定的全域變數和函數必須用一些特殊方法才行。實際上有多種方法可以實現,這裡只介紹兩種方法。
一、在應用程式類中定義
用MFC產生的工程中都有一個名為CxxxApp的類,它派生於CWinApp類。這個類主要進行程式的初始化,產生文檔、視圖對象等工作。我們可以把需要全域訪問的變數和函數定義為這個類的成員變數和成員函數,就可以實現全域訪問了。
從嚴格意義上講,這種變數和函數並不是全域的,因為它仍然只是類中的成員,只是由於我們很容易獲得CxxxApp類的指標,所以我們可以在文檔、視圖、對話方塊以及各種自訂類中訪問到它們,達到與全域變數類似的效果。訪問時用函數“AfxGetApp()”獲得CxxxApp類的指標,用“AfxGetApp()->成員”訪問變數或函數。
例:
Test.h:(應用程式類標頭檔)
class CTestApp : public CWinApp
{
public:
int x; //全域變數
int f(int y); //全域函數
…………
};
Test.cpp:(應用程式類程式檔案)
int CTestApp::f(int y) //全域函數定義
{
y++;
return y;
}
定義在CTestApp類中的變數和函數可以在其它類中被訪問。比如在視圖的某函數中要訪問變數x和函數f():
void CTestView::xyz()
{
CTestApp *app = (CTestApp *)AfxGetApp(); //產生指嚮應用程式類的指標
app->x = 0; //訪問變數x
int z = app->f(1); //訪問函數f()
…………
}
這樣,變數x和函數f()可以視作為全域的。
用這種方法實現的全域變數和全域函數雖比較簡單,但也有缺點,一是訪問不太方便,每次都需要擷取應用程式類的指標;再就是把一些與應用程式類本身無關的變數和函數放在裡面,使這個類看上去怪怪的,破壞了類的封裝。
二、用靜態變數和靜態函數實現
很喜歡API函數的那種調用方法,不論在哪個類中只要用“::API函數”就可以調用了。合理利用靜態類型(static)可以實現與此相似的全域變數和全域函數。
靜態變數和靜態函數有如下性質:
若在一個類中用關鍵字static聲明資料成員,則這個資料成員就只存在一個拷貝,無論該類建立了多少個執行個體,它始終只存在一個,即使該類的執行個體一個也沒建立,它也存在。
若在一個類中用關鍵字static聲明函數,該函數可以用“類名::函數名”方式訪問,無需引用該類的執行個體,甚至這個類的執行個體可以不存在。
利用這個性質實現的全域變數和函數使用起來很方便。
值得注意的是,全域變數和全域函數最好集中封裝,不要在文檔、視圖等類內部定義,這樣用起來才有全域的感覺。
例:
1、添加一個沒有基類的新類,設類名起為CPublic,姑且稱之為公用類
單擊“Insert”菜單下的“New Class”命令,選擇“Class type”為“Generic Class”,在“Name”欄中填入類名“CPublic”,單擊“OK”,則新類建立完畢。
2、包含公用類的標頭檔,使各個類都能訪問它
CPublic的標頭檔應包含在應用程式類的標頭檔中,這樣在其它類中引用CPublic類時就不需要再包含了。
Test.h:(應用程式類標頭檔)
#include "Public.h" //包含公用類標頭檔
class CTestApp : public CWinApp
{
…………
};
3、在公用類中定義全域變數和全域函數,均使用static修飾,靜態變數還必須在類外定義和初始化
Public.h:(公用類標頭檔)
class CPublic
{
public:
CPublic();
virtual ~CPublic();
public:
static int x; //全域變數
static int time; //全域變數
static int f(int y); //全域函數
…………
}
在公用類中對靜態變數進行初始化和定義函數體:
Public.cpp:(公用類程式檔案)
int CPublic::x = 0; //初始化全域變數
int CPublic::time; //定義全域變數
CPublic::CPublic()
{
}
CPublic::~CPublic()
{
}
int CPublic::f(int y) //全域函數,這裡不要再加static
{
y++;
return y;
}
4、全域量的使用
使用變數:CPublic::變數名
使用函數:CPublic::函數()
如在視圖的某函數中訪問變數x和函數f():
void CTestView::xyz()
{
CPublic::x = 0; //訪問變數x
CPublic::time = CPublic::f(1); //訪問函數f()
…………
}
在其它類中訪問x、time和f()的方法與此相同。
5、幾點注意:
① 由於靜態量可獨立於類存在,不需要產生CPublic類的執行個體。
② 待用資料成員的定義和初始化必須在類外進行,如例中x的初始化;變數time雖然沒有初始化,但也必須在類外進行定義。由於沒有產生CPublic類的執行個體,所以它的建構函式和解構函式都不會被執行,在裡面做什麼工作都沒有什麼意義。
③ 如果靜態函數需要訪問CPublic類內的變數,這些變數也必須為靜態。因為非靜態量在不產生執行個體時都不會存在。 如:
class CPublic
{
public:
int x; //內部變數
static int f(int y) //全域函數
{
x++;
return x;
};
…………
};
這裡x雖為類內成員,但如果不產生CPublic類的執行個體,就會出現函數f()存在,而變數x不存在的問題。
總之,用沒有執行個體的類管理全域量是一個不錯的選擇,它具有集中管理,使用方便的好處。當然,除非特別必要,全域量還是少用為好,一個好的編程者決不會隨意濫用全域量的,一個封裝做得不好的程式,在修改維護時會讓你吃足苦頭。