非視窗類中使用定時器的方法(一) (轉)

worldblog發表於2007-12-12
非視窗類中使用定時器的方法(一) (轉)[@more@] 

非視窗類中使用定時器的方法

作者:劉輝:namespace prefix = o ns = "urn:schemas--com::office" />

(網進科技 江蘇 崑山 E:jemmyliu@163.完成時間:年3月12日)

  摘  要  本文主要透過一些簡單的例子,介紹瞭如何在Visual C++的視窗和非視窗類中使用定時器。重點介紹瞭如何用靜態成員和靜態資料成員在非視窗類中使用定時器,同時,又介紹了與定時器相關的知識,例如回撥函式,C++類中的靜態成員,以及模板類中的對映類等。

關鍵字  C++ 類 定時器 靜態函式靜態成員函式 靜態資料成員 回撥函式 對映類

  摘  要:This page introduce how to use timer in window class and none window class of Visual C++ by some simple samples. Use timer in none window class with static member variable and static member function is the important point. At the same time, it also tell about of some knowledge such as about timer, callback function, static member of C++ class and map class CMap of template class.

關鍵字:C++ Class Timer static CALLBACK CMap

1. 引言

  定時器在 的中的作用不可忽略,也隨處可見。設定一個時間間隔每0.5秒或者1秒鐘重新整理一次時鐘,這樣就可以完成一個簡單的電子鐘程式。在不同的工具中定時器的用法也不同,Visual C++中也給我們提供了實現這種功能的方法,而且方法不只一種。在視窗類中是使用定時器比較很簡單,用SetTimer()設定了定時器之後,並在Class Wizard中新增了OnTimer訊息對映後,您就可以在對映函式OnTimer()中新增程式碼實現,來定時完成您的任務,而且還支援任意多個定時器,這種方法大家可能都會用。但是在非視窗的類中,使用定時器就沒那麼簡單了,在類訊息對映中就找不到OnTimer()方法了,類中也沒有hWnd這個屬性,SetTimer()也不能象原來那樣使用了,下面給出了一種既不破壞類的完整性的同時又能巧妙的使用定時器的方法。

2. 相關知識

  在非視窗類中使用定時器,需要了解的知識比較多。首先非視窗類中沒有訊息對映,也沒有象CWnd類具有的SetTimer()方法來設定定時器。沒有訊息對映,就只能靠我們自己定義的回撥函式來處理定時器的訊息,因此大家有必要了解一下回撥函式的概念。因為回撥函式只能用全域性函式或者靜態成員函式來實現,為了維持類的完整性,使用類的靜態成員函式來作為回撥函式,所以我們又需要了解一下靜態資料成員和靜態成員函式的性質。又因為定時器是在我們的程式中產生的,這又需要來管理定時器,所以又用到了對映表類CMap,因此介紹一下CMap的簡單用法也是必不可少的。

2.1 回撥函式

所謂回撥函式就是按照一定的形式由你定義並編寫實現內容,當發生某種事件時,而由或其它函式來的函式。

使用回撥函式實際上就是在呼叫某個函式(通常是函式)時,將自己編寫的一個函式(也就是回撥函式)的地址作為引數傳遞給那個函式。而那個函式在需要的時候,也就是某種事情發生的時候,利用傳遞的函式地址呼叫回撥函式,這時你可以利用這個機會在回撥函式中處理訊息或完成一定的操作。回撥函式只能是全域性函式,或者是靜態函式,因為這個函式只是在這個類中使用,所以為了維護類的完整性,我們用類的靜態成員函式來做回撥函式。

2.2 C++類中的靜態成員

在C語言中,宣告一個資料為靜態型別,意味著該變數的生存週期是靜態的,即在程式的開始時即分配,到程式終止時才釋放。但在C++中,宣告一個類中的成員為靜態型別,則意味著該類的所有例項只有該成員的一個複製。也就是說,不管應用程式中建立了這個類的多少個,其靜態成員只有一個副本,該副本為這個類的所有物件例項所共享,而對於非靜態成員,每個類物件例項都有自己的複製。例如:

class CPerson

{

public:

  CString szName;

  static CString szCompanyName;

  CPerson();

  virtual ~CPerson();

};

  接著用該類宣告一個例項 CPerson me;

  對於同一家公司員工,每個人都有不同的姓名,但是他們的公司名字是一樣的,所以就可以用一個靜態型別來儲存,這樣所有的員工都共享這個公司名稱,只要一位員工了公司名稱,則所有員工的公司名稱就被更新了。

靜態成員被當作該類型別的全域性物件,可以把一個靜態資料成員和靜態成員函式當成全域性變數和函式那樣去和訪問,但又被隱藏在類的內部,並且清楚地與這個類相聯絡但又不是全域性物件,同全域性物件相比,使用靜態成員有兩個優勢:

  (1) 靜態成員沒有進入程式的全域性名字空間,它屬於類,它的名字只在類的範圍內有效,因此不存在與程式中其他全域性名字衝突的可能性。

  (2) 可以實現資訊隱藏,並可以保持類的完整性,可以是private(私有的)成員、public(公有的)成員或者protected(保護的)成員,而全域性物件不能。

2.2.1 靜態資料成員

使用靜態資料成員可以節省,因為它是所有物件所公有的,因此,對多個物件來說,靜態資料成員只儲存一處,供所有物件共用。靜態資料成員的值對每個物件都是一樣,但它的值是可以更新的。只要對靜態資料成員的值更新一次,就可以保證所有物件都能夠訪問到被更新後的值,這樣可以提高和節省記憶體空間。

在類中將一個成員變數宣告為靜態的,與宣告普通變數的唯一區別就是在其定義前加一個static。

象上面的例子中那樣宣告:

static CString szCompanyName。

靜態資料成員顯式初始化與一般資料成員初始化不同。靜態資料成員顯式初始化的格式如下:

  ::=

對於上面的例子這樣初始化:

CString CPerson::szCommpanyName = "網進科技",

這表明:

  (1) 初始化在類體外進行,而前面不加static,以免與一般靜態變數或物件相混淆。

  (2) 初始化時不加該成員的訪問控制符private,public等。

(3) 初始化時使用作用域運算子來標明它所屬類,因此,靜態資料成員是類的成員,而不是物件的成員。

  在類的成員函式中可以直接引用該類的靜態資料成員,而不必使用成員訪問運算子。但是在非成員函式中,我們必須一兩種方式之一訪問靜態資料成員。

(1) 使用成員訪問運算子。

例如:me是CPerson的一個例項,在非成員函式中可以這樣應用其中的靜態資料成員:

CString TheCommpanyName = me.CommpanyName。

(2) 因為類靜態資料成員只有一個複製,所以它不一定要透過物件或者指標來訪問。方法二就是用被類名限定修飾的名字直接訪問它。當我們不透過類的成員訪問運算子訪問靜態資料成員時,必須指定類名以及緊跟其後的域運算子,因為靜態成員不是全域性物件,所以我們不能在全域性域中找到它。如:

CString TheCommpanyName = CPerson::CommpanyName。

  順便說一句靜態資料成員還有兩個特點:

  (1) 靜態資料成員的型別可以是其所屬類,而非靜態資料成員只能被宣告為該類的物件的指標或引用。

  (2) 靜態資料成員可以被作為類成員函式的預設實參,而非靜態成員不能。

2.2.1 靜態成員函式

  靜態成員函式的宣告與普通函式的唯一區別就是在前面加一個static。

  通常,當前物件的地址(this)是被隱含地傳遞到被呼叫的非靜態成員函式的。靜態成員函式具有類的範圍,同非靜態成員函式相比,靜態成員函式沒有this引數,因此它不能訪問一般的資料成員,而只能訪問靜態資料成員、列舉或巢狀型別和其他的靜態成員函式。這樣使用靜態成員函式在速度上可以比全域性函式有少許的增長,它不僅沒有傳遞this指標所需的額外的花費,而且還有使函式在類內的好處。如果靜態成員函式中要引用非靜態成員時,可透過物件來引用。

  我們可以用成員訪問運算子點(.)和箭頭(->)為一個類物件或指向類物件的指標訪問靜態成員函式,也可以用限定修飾名直接訪問靜態成員函式,而無需宣告類物件。

靜態成員函式遵循:

(1) 不能用成員選擇符(.或->)訪問非靜態成員。

(2) 不能說明為虛擬函式。

(3) 不能與有相同引數型別的非靜態成員函同名。

(4) 不能宣告為const或volatile。

(5) 出現在類體外的函式定義不指定關鍵字static

2.3 對映表類CMap

  對映表類(CMap)是MFC集合類中的一個模板類,也稱作為“字典”,就像一種只有兩列的表格,一列是關鍵字,一列是資料項,它們是一一對應的。關鍵字是唯一的,給出一個關鍵字,對映表類會很快找到對應的資料項。對映表的查詢是以雜湊表的方式進行的,因此在對映表中查詢數值項的速度很快。舉個例子來說吧,公司的所有職員都有一個工號和自己的姓名,工號就是姓名的關鍵字,給出一個工號,就可以很快的找到相應的姓名。對映類最適用於需要根據關鍵字進行檢索的場合,我們的程式中就用對映表來儲存計時器標誌值和類例項指標,用計時器的標誌值作為關鍵字。

3. 讓靜態成員函式也能訪問非靜態成員函式

從上面的敘述可以看出來,在類中靜態成員函式只能引用靜態資料成員和靜態成員函式,如何才能讓靜態成員函式也能引用非靜態的成員函式和成員變數呢?這也是我們後面將會用到的。

分析一下靜態成員函式和非靜態成員函式的區別,我們會發現非靜態成員函式之所以能訪問所有的成員函式和成員變數,是因為它有個隱含的引數this,訪問成員函式和成員變數的時候,實際上是在前面新增了個引用的符號"this->",所以我們就可以試著將this這個指標作為靜態成員函式的一個引數傳遞進去,這樣不就可以在靜態成員函式中訪問所有的成員函式和成員變數了嗎?下面給出一個實現的例子:

Person.h如下:

class CPerson 

{

public:

  //該例項的一句座右銘

  CString szMotto;

  //用於儲存該例項的指標

  CPerson* pThis;

  //非靜態成員函式,彈出該例項的座右銘

  void GetMotto();

  //靜態成員函式,彈出該例項的座右銘

  static void GetMottoStaic(CPerson* pPerson);

  CPerson();

  virtual ~CPerson();

};

Person.cpp檔案如下:

#include "stdafx.h"

#include "Person.h"

 

CPerson::CPerson()

{

  pThis = this;

}

 

CPerson::~CPerson()

{

}

 

void CPerson::GetMotto()

{

  AfxMessageBox(szMotto);

}

 

void CPerson::GetMottoStaic(CPerson* pPerson)

{

  pPerson->GetMotto();

}

  在需要的地方就可以如下訪問靜態成員函式:

 m_Person.szMotto = "我的座右銘是:這是由靜態函式訪問非靜態函式的結果!";

 m_Person.GetMottoStaic(m_Person.pThis);

 其實這個例子實際上是沒有什麼意義的,這樣做的目的只是為了演示如何實現這個方法而已。

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-992367/,如需轉載,請註明出處,否則將追究法律責任。

相關文章