複習上一篇:C++ 的 static -靜態變數與函式詳細說明
https://husking-studio.com/cpp-static/
前面提到, 靜態成員函式 只能存取 靜態成員變數。
那如果我真的想要用靜態成員函式 存取 一般成員變數呢?
※重要聲明:「用靜態成員函式存取一般成員變數」是研究與實驗性質的嘗試,是為了在研究過程中更了解「 靜態宣告 」的特性,實務上是非常不建議這樣使用的。
非常不建議的原因是,靜態成員函式本來就是為了存取靜態成員變數存在,而想存取一般成員變數,本來就有一般成員函式可以用了。所以「用靜態成員函式來存取一般成員變數」,不只繞了路,還會造成對「靜態」定義的混淆,沒有任何好處喔。
用一個指向自己的靜態指標可以嗎?再用靜態成員函式去拿自己,再拿自己的一般成員變數可以嗎?我們來試試看!
#include <iostream>
using namespace std;
class A
{
public:
static int m_nNum;//宣告static member variable
static A* m_pThis;//宣告一個指向自己的靜態指標
private:
int m_nNum2;
int m_nNum3;
public:
A() { m_nNum2 = 10; m_nNum3 = 20; m_pThis = this;}
static int GetNum2() { return m_pThis->m_nNum2; }
static int StaticGetNum3() { return m_pThis->GetNum3(); }
void SetNum3(int n) { m_nNum3 = n; }
int GetNum3() { return m_nNum3; }
};
int A::m_nNum = 0;
A* A::m_pThis = 0;
int main()
{
cout << "A::m_nNum = " << A::m_nNum << endl;
//cout<<A::GetNum2()<<endl; //這行是會當掉的,因為 m_pThis=0
cout << endl;
cout << "建立物件a1" << endl;
A a1;
cout << "A::m_nNum = " << A::m_nNum << endl;
cout << "a1.m_nNum = " << a1.m_nNum << endl;
cout << "a1.GetNum2() = " << a1.GetNum2() << endl;
cout << "a1.StaticGetNum3() = " << a1.StaticGetNum3() << endl;
cout << endl;
system("pause");
return 0;
}
執行結果
A::m_nNum = 0 建立物件a1 A::m_nNum = 0 a1.m_nNum = 0 a1.GetNum2() = 10 a1.StaticGetNum3() = 20 |
好像可以呢,可以用靜態成員函式 GetNum2() 取得 一般成員變數 m_nNum2,也可以用靜態成員函式 StaticGetNum3() 呼叫 一般成員函式 GetNum3()。
再新增一個物件看看
int main()
{
cout << "建立物件a1" << endl;
A a1;
cout << "A::m_nNum = " << A::m_nNum << endl;
cout << "a1.m_nNum = " << a1.m_nNum << endl;
cout << "a1.GetNum2() = " << a1.GetNum2() << endl;
cout << "a1.StaticGetNum3() = " << a1.StaticGetNum3() << endl;
cout << endl;
cout << "建立物件a2" << endl;
A a2;
cout << "A::m_nNum = " << A::m_nNum << endl;
cout << "a2.m_nNum = " << a2.m_nNum << endl;
cout << "a2.GetNum2() = " << a2.GetNum2() << endl;
cout << "執行 a2.SetNum3(100) 把 a2 的 m_nNum3 從 20 設成 100" << endl;
a2.SetNum3(100);
cout << "a2.StaticGetNum3() = " << a2.StaticGetNum3() << endl;
cout << endl;
cout << "回到物件a1" << endl;
//下面這行會有問題
cout << "a1.StaticGetNum3() = " << a1.StaticGetNum3() << endl;
cout << "a1.GetNum3() = " << a1.GetNum3() << endl;
cout << endl;
system("pause");
return 0;
}
執行結果
建立物件a1 A::m_nNum = 0 a1.m_nNum = 0 a1.GetNum2() = 10 a1.StaticGetNum3() = 20 建立物件a2 A::m_nNum = 0 a2.m_nNum = 0 a2.GetNum2() = 10 執行 a2.SetNum3(100) 把 a2 的 m_nNum3 從 20 設成 100 a2.StaticGetNum3() = 100 回到物件a1 a1.StaticGetNum3() = 100 a1.GetNum3() = 20 |
值得注意的是 a1.StaticGetNum3() = 100,a1 的 m_nNum3 是 100 嗎?a1 的 m_nNum3 明明就是 20,而 a2 的 m_nNum3 才是100,那為什麼這裡會錯了呢?
主要的問題是來自於 m_pThis,我們為了讓靜態成員函式可以存取一般成員函式和成員變數,所以使用 m_pThis 指向自己來取得一般成員函式和成員變數,而且為了讓靜態成員函式可以使用 m_pThis 指標,還把 m_pThis 指標宣告成 static 的。
宣告成 static 就表示他是所有物件共用的,所以當產生 a1 物件時,m_pThis 是指向 a1 物件的,而產生 a2 物件時 m_pThis 就改指向 a2 物件了,所以就算透過 a1 物件取得 m_pThis,也都會取得 a2 物件了。
想要用靜態成員函式 存取 一般成員變數,那又要怎麼解決這個 m_pThis 的問題呢?
就是把物件自己當成參數傳進靜態成員函式裡。我們先把 m_pThis 拿掉。
#include <iostream>
using namespace std;
class A
{
public:
static int m_nNum; //宣告static member variable
private:
int m_nNum2;
int m_nNum3;
public:
A() { m_nNum2 = 10; m_nNum3 = 20;}
static int GetNum2(A *a) { return a->m_nNum2; }
static int StaticGetNum3(A* a) { return a->GetNum3(); }
void SetNum3(int n) { m_nNum3 = n; }
int GetNum3() { return m_nNum3; }
};
int A::m_nNum = 0;
int main()
{
cout << "建立物件a1" << endl;
A a1;
cout << "A::m_nNum = " << A::m_nNum << endl;
cout << "a1.m_nNum = " << a1.m_nNum << endl;
cout << "a1.GetNum2(&a1) = " << a1.GetNum2(&a1) << endl;
cout << "a1.StaticGetNum3(&a1) = " << a1.StaticGetNum3(&a1) << endl;
cout << endl;
cout << "建立物件a2" << endl;
A a2;
cout << "A::m_nNum = " << A::m_nNum << endl;
cout << "a2.m_nNum = " << a2.m_nNum << endl;
cout << "a2.GetNum2(&a2) = " << a2.GetNum2(&a2) << endl;
cout << "執行 a2.SetNum3(100) 把 a2 的 m_nNum3 從 20 設成 100" << endl;
a2.SetNum3(100);
cout << "a2.StaticGetNum3(&a2) = " << a2.StaticGetNum3(&a2) << endl;
cout << "a2.GetNum3() = " << a2.GetNum3() << endl;
cout << endl;
cout << "回到物件a1" << endl;
cout << "a1.StaticGetNum3(&a1) = " << a1.StaticGetNum3(&a1) << endl;
cout << "a1.GetNum3() = " << a1.GetNum3() << endl;
cout << endl;
system("pause");
return 0;
}
執行結果
建立物件a1 A::m_nNum = 0 a1.m_nNum = 0 a1.GetNum2(&a1) = 10 a1.StaticGetNum3(&a1) = 20 建立物件a2 A::m_nNum = 0 a2.m_nNum = 0 a2.GetNum2(&a2) = 10 執行 a2.SetNum3(100) 把 a2 的 m_nNum3 從 20 設成 100 a2.StaticGetNum3(&a2) = 100 a2.GetNum3() = 100 回到物件a1 a1.StaticGetNum3(&a1) = 20 a1.GetNum3() = 20 |
恩,解決了。其實 m_pThis 也不是不能用,只不過要注意 static 的特性就是了。
咦~這樣的話,前面是透過 a1 還是 a2 去呼叫還有差別嗎?當然沒有囉,所以呼叫時把前面的物件拿掉也可以。
#include <iostream>
using namespace std;
class A
{
public:
static int m_nNum; //宣告static member variable
private:
int m_nNum2;
int m_nNum3;
public:
A() { m_nNum2 = 10; m_nNum3 = 20; }
static int GetNum2(A* a) { return a->m_nNum2; }
static int StaticGetNum3(A* a) { return a->GetNum3(); }
void SetNum3(int n) { m_nNum3 = n; }
int GetNum3() { return m_nNum3; }
};
int A::m_nNum = 0;
int main()
{
cout << "建立物件a1" << endl;
A a1;
cout << "A::GetNum2(&a1) = " << A::GetNum2(&a1) << endl;
cout << "A::StaticGetNum3(&a1) = " << A::StaticGetNum3(&a1) << endl;
cout << endl;
cout << "建立物件a2" << endl;
A a2;
cout << "A::GetNum2(&a2) = " << A::GetNum2(&a2) << endl;
cout << "執行 a2.SetNum3(100) 把 a2 的 m_nNum3 從 20 設成 100" << endl;
a2.SetNum3(100);
cout << "A::StaticGetNum3(&a2) = " << A::StaticGetNum3(&a2) << endl;
cout << endl;
system("pause");
return 0;
}
建立物件a1 A::GetNum2(&a1) = 10 A::StaticGetNum3(&a1) = 20 建立物件a2 A::GetNum2(&a2) = 10 執行 a2.SetNum3(100) 把 a2 的 m_nNum3 從 20 設成 100 A::StaticGetNum3(&a2) = 100 |
還要把物件自己傳進去,那跟一般的全域函式有什麼不一樣?
不一樣喔,來看看下面的例子
#include <iostream>
using namespace std;
class A
{
public:
static int m_nNum;
private:
int m_nNum2;
public:
A() { m_nNum2 = 10;}
static int GetNum2(A* a) { return a->m_nNum2; }
};
int A::m_nNum = 0;
int GlobalGetNum2(A* a)
{
return a->m_nNum2;//不能存取
}
int main()
{
cout << "建立物件a1" << endl;
A a1;
//下面這兩行有什麼不一樣?
cout << "A::GetNum2(&a1) = " << A::GetNum2(&a1) << endl;
cout << "GlobalGetNum2(&a1) = " << GlobalGetNum2(&a1) << endl;//不能存取
cout << endl;
system("pause");
return 0;
}
一般的全域函式 GlobalGetNum2() 就不能存取 private 的 m_nNum2 了啊。
如果 m_nNum2 是 public 的,那靜態成員函式 GetNum2() 和 一般的全域函式 GlobalGetNum2() 確實就會沒什麼差別。
※再次聲明:「用靜態成員函式存取一般成員變數」是研究與實驗性質的嘗試,是為了在研究過程中更了解「 靜態宣告 」的特性,實務上是非常不建議這樣使用的。
非常不建議的原因是,靜態成員函式本來就是為了存取靜態成員變數存在,而想存取一般成員變數,本來就有一般成員函式可以用了。所以「用靜態成員函式來存取一般成員變數」,不只繞了路,還會造成對「靜態」定義的混淆,沒有任何好處喔。
回上一篇:C++ 的 static -靜態變數與函式詳細說明
https://husking-studio.com/cpp-static/
謝謝
不客氣 ^__^