static關鍵字的用法
static 是c++中很常用的修飾符,它被用來控制變量的存儲方式和可見性,下面我將從 static 修飾符的產生原因、作用談起,全面分析static 修飾符的實質。
static 的兩大作用:
一、控制存儲方式:static被引入以告知編譯器,將變量存儲在程序的靜態存儲區而非棧上空間。1、引出原因:函數內部定義的變量,在程序執行到它的定義處時,編譯器為它在棧上分配空間,大家知道,函數在棧上分配的空間在此函數執行結束時會釋放掉,這樣就產生了一個問題: 如果想將函數中此變量的值保存至下一次調用時,如何實現?最容易想到的方法是定義一個全局的變量,但定義為一個全局變量有許多缺點,最明顯的缺點是破壞了此變量的訪問范圍(使得在此函數中定義的變量,不僅僅受此函數控制)。2、 解決方案:因此c++ 中引入了static,用它來修飾變量,它能夠指示編譯器將此變量在程序的靜態存儲區分配空間保存,這樣即實現了目的,又使得此變量的存取范圍不變。
二、控制可見性與連接類型 :static還有一個作用,它會把變量的可見范圍限制在編譯單元中,使它成為一個內部連接,這時,它的反義詞為”extern”.static作用分析總結:static總是使得變量或對象的存儲形式變成靜態存儲,連接方式變成內部連接,對于局部變量(已經是內部連接了),它僅改變其存儲方式;對于全局變量(已經是靜態存儲了),它僅改變其連接類型。
類中的static成員:
一、出現原因及作用:
1、需要在一個類的各個對象間交互,即需要一個數據對象為整個類而非某個對象服務。
2、同時又力求不破壞類的封裝性,即要求此成員隱藏在類的內部,對外不可見。
類的static成員滿足了上述的要求,因為它具有如下特征:有獨立的存儲區,屬于整個類。
二、注意:
1、對于靜態的數據成員,連接器會保證它擁有一個單一的外部定義。靜態數據成員按定義出現的先后順序依次初始化,注意靜態成員嵌套時,要保證所嵌套的成員已經初始化了。消除時的順序是初始化的反順序。
2、類的靜態成員函數是屬于整個類而非類的對象,所以它沒有this指針,這就導致了它僅能訪問類的靜態數據和靜態成員函數。
如下是對靜態關鍵字的一些說明。
1、靜態全局變量
定義:在全局變量前,加上關鍵字 static 該變量就被定義成為了一個靜態全局變量。
特點:
A、該變量在全局數據區分配內存。
B、初始化:如果不顯式初始化,那么將被隱式初始化為0。
C、訪變量只在本源文件可見,嚴格的講應該為定義之處開始到本文件結束。
例(摘于C++程序設計教程---錢能主編P103):
//file1.cpp
#include<iostream.h>
void fn();
extern int n;
void main()
{
n=20;
cout << n << endl;
fn();
}
//file2.cpp
#include<iostream.h>
static int n; //定義靜態全局變量,初始化為0;
void fn()
{
n++;
cout << n << endl;
}
文件分別編譯能通過,但連接時file1.cpp 中的變量n找不到定義,產生連接錯誤。
D、文件作用域下聲明的const的常量默認為static存儲類型。
2、靜態局部變量
定義:在局部變量前加上static關鍵字時,就定義了靜態局部變量。
特點:
A、該變量在全局數據區分配內存。
B、初始化:如果不顯式初始化,那么將被隱式初始化為0。
C、它始終駐留在全局數據區,直到程序運行結束。但其作用域為局部作用域,當定義它的函數或 語句塊結束時,其作用域隨之結束。
3、靜態函數(注意與類的靜態成員函數區別)
定義:在函數的返回類型前加上static關鍵字,函數即被定義成靜態函數。
特點:
A、靜態函數只能在本源文件中使用(這是與普通函數區別)
例(摘于C++程序設計教程---錢能主編P103):
//file1.cpp
void fn();
void staticFn()
void main()
{
fn();
staticFn();
}
//file2.cpp
#include<iostream.h>
static void staticFn();
void fn();
void fn()
{
staticFn();
cout << "this is fn() \n";
}
void staticFn()
{
cout << "this is staticFn() \n";
}
連接時,將產生找不到函數staticFn()定義的錯誤。
B、主意事項
在文件作用域下聲明的inline函數默認為static類型。
二、面象對象中的static關鍵字(主要指類中的static關鍵字)
1、靜態數據成員
特點:
A、內存分配:在程序的全局數據區分配。
B、初始化和定義:
a、靜態數據成員定義時要分配空間,所以不能在類聲明中定義。
b、為了避免在多個使用該類的源文件中,對其重復定義,所在,不能在類的頭文件中定義。
c、靜態數據成員因為程序一開始運行就必需存在,所以其初始化的最佳位置在類的內部實現。
C、特點
a、對相于 public,protected,private 關鍵字的影響它和普通數據成員一樣,
b、因為其空間在全局數據區分配,屬于所有本類的對象共享,所以,它不屬于特定的類對象,在沒產生類對象時其作用域就可見,即在沒有產生類的實例時,我們就可以操作它。
D、訪問形式
a、 類對象名.靜態數據成員名
b、 類類型名:: 靜態數據成員名
E、靜態數據成員,主要用在類的所有實例都擁有的屬性上。比如,對于一個存款類,帳號相對 于每個實例都是不同的,但每個實例的利息是相同的。所 以,應該把利息設為存款類的靜態數據成員。這有兩個好處,第一,不管定義多少個存款類對象,利息數據成員都共享分配在全局區的內存,所以節省存貯空間。第 二,一旦利息需要改變時,只要改變一次,則所有存款類對象的利息全改變過來了,因為它們實際上是共用一個東西。
2、靜態成員函數
特點:
A、靜態成員函數與類相聯系,不與類的對象相聯系。
B、靜態成員函數不能訪問非靜態數據成員。原因很簡單,非靜態數據成員屬于特定的類實例。
作用:
主要用于對靜態數據成員的操作。
調用形式:
A、類對象名.靜態成員函數名()
B、類類型名:: 靜態成員函數名()