2010-11-09 271 views
0

我看到下面的代碼:
http://sourcemaking.com/design_patterns/singleton/cpp/1靜態成員變量可以調用非靜態成員函數嗎?

class GlobalClass 
{ 
private: 
    int m_value; 
    static GlobalClass *s_instance; 
    GlobalClass(int v = 0) 
    { 
     m_value = v; 
    } 
public: 
    int get_value() 
    { 
     return m_value; 
    } 
    void set_value(int v) 
    { 
     m_value = v; 
    } 
    static GlobalClass *instance() 
    { 
     if (!s_instance) 
      s_instance = new GlobalClass; 
     return s_instance; 
    } 
}; 

GlobalClass *GlobalClass::s_instance = 0; 

void foo(void) 
{ 
    GlobalClass::instance()->set_value(1); // static variable calls non-static functions 
    cout << "foo: global_ptr is " << GlobalClass::instance()->get_value() << '\n'; 
} 

據我所知(請糾正我,如果我錯了這裏),

  1. 靜態函數只能訪問(讀/寫)靜態成員變量

  2. 非靜態函數可以訪問(寫入/讀取)靜態成員變量

基於上面的示例,似乎靜態變量可以訪問非靜態函數。
這是正確的嗎?

回答

5

變量不叫什麼

(這並沒有真正解決示例代碼,但它的兩個「規則」的代碼下面列出的糾正一個誤解)

靜態成員函數是一個成員,並且可以訪問其類的所有公共,受保護和私有成員,包括靜態和實例。

但是,靜態成員函數沒有this指針,因此要訪問實例成員,需要指定實例。

+2

靜態成員函數不能訪問非靜態成員變量。 – q0987 2010-11-09 04:48:54

+5

@ q0987:是的,它可以。我可以給你一個例子,但我真的希望你停下來,首先想想我的答案。學習思考軟件是學習編程非常重要的一部分。 – 2010-11-09 05:05:30

+3

以下是您的示例:http://ideone.com/gX5wF – 2010-11-09 05:10:43

3

instance顧名思義就是返回一個指向實例的指針。它也使用靜態實例指針字段s_instance。這是靜態的這一事實意味着每個類只有一個s_instance字段。一旦獲得該實例指針(來自instance),就可以像使用其他實例指針一樣使用它。您通過靜態方法獲得的事實,並且該方法使用靜態字段是無關緊要的。

靜態方法本身是有效的;它不會隱式或顯式使用this

+0

比我能管理的更簡潔。我認爲他也感到困惑,s_instance本身是靜態的,而不僅僅是他得到指針的方法。 – Phil 2010-11-09 07:52:11

+0

@菲爾,好點。我添加了一些關於該領域的討論。 – 2010-11-09 15:58:12

4

看來,一個靜態變量可以訪問非靜態函數。

你的代碼並不完全符合你剛纔所說的。

爲了理解它在做什麼,讓我們回過頭來談談class的真正含義。類定義新類型。另一種類型是int。一個int實例可以位於函數局部變量或參數中,它可以通過調用new int存儲在堆上,它可以是全局的,只需在文件範圍內聲明一個即可。他們都不知道或不在乎他們的存儲位置,但他們都是int類型的實例。

當您創建class的實例時,您正在創建所使用的空間以及該類實例上的行爲,並且這些行爲同樣適用於每個實例。

類也可以做一些不是定義其實例的數據和行爲的一部分,而這些是類的靜態成員。

由於這些概念基本上是分開的,所以它們並不真正互相干擾。實際上,您可以讓該類的靜態成員之一引用該類的一個實例,而這正是單例模式的例子。

所以實際上發生了什麼,從一開始就是創建一個類的實例,使用new GlobalClass,然後將指針保持在某個位置。碰巧指針被保存爲定義剛剛創建的實例類型的同一類的靜態成員。

然後GlobalClass提供了使用該實例的機制。當你調用GlobalClass::instance()時,它會讀取一個允許的靜態類變量。該變量包含一個指針,該指針在解除引用時(通過->)會導致我們先前創建的一個對象,並且該對象因爲它是GlobalClass的一個實例,現在允許訪問實例變量。

+0

Hello TokenMacGuy,GlobalClass :: instance()返回s_instance,它是一個靜態成員變量。所以我假設這個函數返回一個靜態成員變量。我對麼? - 謝謝 – q0987 2010-11-09 04:44:01

+0

@ q0987 - 是的,這是正確的。靜態方法不能訪問非靜態方法,但是一個實例(靜態或其他)可以訪問兩者。 – Phil 2010-11-09 04:49:02

+0

@菲爾,這是我感到困惑的一點。由於返回的實例是一個靜態變量。這個靜態變量如何調用非靜態成員函數set_value並更改非靜態成員變量m_value?換句話說,一個靜態變量如何確定使用哪個「this」? - 謝謝 – q0987 2010-11-09 04:57:03

1

技術問題已經發布在其他答案中,我只是添加一個試圖幫助解決混亂的例子。想象一下,你創建了一個Human類來表示一個人,它可以擁有諸如眼睛的顏色,名稱等等的屬性以及定義諸如步行,跳躍等動作的方法......這些屬性和方法是特定的給人類的每個實例:一個特定的人可能有藍眼睛,你可以讓她說話。

在不同的層次上,可能會有不屬於實例的特性或行爲,而是涉及到整個人類,比如誰是最高或最高級的人類。那些被宣稱爲靜態屬於整個人類,而不是每個人。

現在,一旦你從班上獲得一個人,說最高,那個人是一個人,因此你可以要求任何你想要的財產,或者你可以要求你需要的任何行動:Human::get_tallest().get_something_from_cupboard()將要求最高(get_tallest())集體中的人(集體訴訟),然後請求特定的個人爲您執行某項操作(get_something_from_cupboard()),這是由特定的實例執行的操作。