靜態成員變量
不同的對象占用不同的內存,這就使不同對象的成員變量相互獨立,互不影響。給定兩個對象a
和b
,假設我們修改了a.a
,b.a
並不會受到影響。
如果我們想要在多個對象之間共享一個數據,這就用到了靜態成員變量。
- 靜態成員變量是一種特殊的成員變量,被static修飾。
- 只能被定義一次,儲在全局常量區,不占用對象的儲存空間這就意味靜態成員不隨對象的創建而分配內存,也不隨對象的銷毀而釋放內存。
- 被同類的全體成員共享,單靜態成員變量只有一個實例存在,與類定義了多少對象無關,
也就是說靜態成員是與該類相關的,而不是與類的實例對象相關
靜態成員變量不能在類中初始化,因為靜態成員變量是被所有的對象所共享,若在類中初始化的話每次創建一個新的對象它的值都要被修改。
靜態成員變量不能用初始化列表進行初始化,靜態成員變量只能在類外進行初始化,一般缺省值為0。
type class_name::name = value;
一個簡單的例子,比如我們要記錄創建了幾個對象
#include <bits/stdc++.h>
using namespace std;
class A {
private :
static int a;
public :
//A(int x) : a(x) {} 這句話是錯誤的,不能用初始化列表進行賦值
A() { a++; }
void print() { printf("%d", a); }
};
int A::a; //缺省值為0
int main() {
A a, b, c, d;
a.print();
return 0;
}
輸出
4
而且,靜態成員變量既可以通過對象名訪問,也可以通過類名訪問,但要遵循public
,private
,protected
的訪問原則,如上面程序中不能直接訪問靜態成員變量a。
#include <bits/stdc++.h>
using namespace std;
class A {
public :
static int a;
A() { a++; }
};
int A::a;
int main() {
A a, b, c, d;
printf("%d\n", a.a); //通過對象名訪問
printf("%d\n", b.a); //通過對象名訪問
printf("%d\n", A::a); //通過類名訪問
return 0;
}
輸出
4
4
4
當通過變量名訪問時,對於不同的對象,訪問的地址相同。
靜態成員函數
static不僅可以聲明靜態成員變量,也可以聲明靜態成員函數,靜態成員函數只能訪問靜態成員,靜態成員函數和外部的其他函數。
像靜態成員變量一樣,靜態成員函數也可以通過對象名和類名來調用
#include <bits/stdc++.h>
using namespace std;
class A {
public :
static int a;
A() { a++; }
static int query() { return a; }
};
int A::a;
int main() {
A a, b, c, d;
printf("%d\n", a.query()); //通過對象名訪問
printf("%d\n", A::query()); //通過類名訪問
return 0;
}
輸出
4
在講this指針時提到過,編譯器在編譯成員函數時,會隱式的添加一個this形參,並把對象的地址給this,通過this來訪問成員。
因為靜態函數可以直接通過類來調用,不需要對象的地址,所以靜態成員函數沒有this指針,所以靜態成員函數即使在沒有實例對象的情況下,也可以被調用。
#include <bits/stdc++.h>
using namespace std;
class A {
public :
static int a;
static int query() { return a; }
};
int A::a = 10;
int main() {
printf("%d\n", A::query()); //沒有對象時直接調用
return 0;
}
static函數沒有this指針,所以不能訪問類的非靜態成員變量,不能調用非靜態的成員函數。
int query_() {
return 10;
}
class A {
static int a;
int b;
public :
int _query() { return a; }
static int query() { return b; } //錯誤,b不是靜態成員變量
static void add(int x) { a += query(); } //可以,可以調用靜態成員函數
static void _add(int x) { a += _query(); } //錯誤,_query()不是靜態成員函數
static void add_(int x) { a += query_(); } //可以,可以調用外部的其他函數
};
靜態成員函數和普通成員函數的區別
- 靜態成員函數沒有this指針,只能訪問靜態成員
- 普通成員函數有this指針,可以訪問類中的任意成員