1. 程式人生 > >C++那些細節--static關鍵字

C++那些細節--static關鍵字

static也是我們經常用到的關鍵字,關於static有很多用法,而且在面向過程和麵向物件程式設計中,static有著不同的意義。之前總是記不住,於是,本人強迫症又發作了,一定要搞懂它!!!

一.面向過程程式設計中的static關鍵字

1.靜態全域性變數

靜態全域性變數:
// C++Test.cpp : 定義控制檯應用程式的入口點。
//

#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;

static int s_test;
int nons_test;

int _tmain(int argc, _TCHAR* argv[])
{
	
	//靜態全域性變數預設初始化為0
	cout<<"static :"<<s_test<<endl;
	//非靜態全域性變數預設初始化也是0,但如果是區域性非靜態變數,在VS中直接報錯,不能通過編譯
	cout<<"non-static: "<<nons_test<<endl;

	system("pause");
	return 0;
}

結果: static :0
non-static: 0
請按任意鍵繼續. . .
我們在執行程式時,記憶體分為程式碼區,全域性資料區,堆區,棧區。正常的臨時變數auto等都在棧區,生命週期是函式結束,而new出來的物件一般都在堆區,宣告週期由我們控制,new時開始,delete時結束。而全域性資料區則儲存全域性變數以及靜態變數,他們的生命週期是整個程式的執行週期。 使用靜態全域性變數和使用普通全域性變數的差別: 1)如果全域性變數在標頭檔案中,或者使用和定義都在同一個檔案中,靜態全域性變數和普通全域性變數是相同的。
//StaticTest.h標頭檔案中分別定義靜態全域性變數和普通全域性變數
static int static_num = 20;
int nonstatic_num = 30;

// C++Test.cpp : 定義控制檯應用程式的入口點。
//全域性變數在標頭檔案或者本檔案中兩者沒有什麼區別

#include "stdafx.h"
#include <iostream>
#include <string>
#include "StaticTest.h"
#include "StaticTest1.h"
using namespace std;


int _tmain(int argc, _TCHAR* argv[])
{
	
	//如果靜態變數在標頭檔案中或者本檔案中,可以訪問靜態全域性變數
	cout<<"static :"<<static_num<<endl;
	//如果靜態變數在標頭檔案中或者本檔案中,可以訪問非靜態全域性變數
	cout<<"non-static: "<<nonstatic_num<<endl;

	system("pause");
	return 0;
}

結果: static :20
non-static: 30
請按任意鍵繼續. . .
2)如果全域性變數在.cpp檔案中,普通全域性變數是全域性可見的,即其他檔案也可見,但是要使用時,就要在其他檔案中新增extern關鍵字。而且如果不新增的話,在這個檔案再宣告同名的變數,是會報錯的。但是使用靜態全域性變數就可以解決這個問題,靜態全域性變數在其他檔案中是不可見的,我們不需要關注其他檔案中的全域性變數,也不會出現不能使用同名全域性變數的問題啦!
//.h檔案
#ifndef __STATICTEST1_H_
#define __STATICTEST1_H_
#pragma once
class StaticTest1
{
public:
	StaticTest1(void);
	virtual ~StaticTest1(void);
};
#endif

//.cpp檔案
#include "stdafx.h"
#include "StaticTest1.h"

//在.cpp檔案中定義全域性變數
static int static_test = 10;
int nonstatic_test = 20;

StaticTest1::StaticTest1(void)
{
}


StaticTest1::~StaticTest1(void)
{
}
main函式檔案:
// C++Test.cpp : 定義控制檯應用程式的入口點。
//

#include "stdafx.h"
#include <iostream>
#include "StaticTest1.h"
using namespace std;

extern int nonstatic_test;
extern int static_test;

int _tmain(int argc, _TCHAR* argv[])
{
	
	//如果靜態變數在其他.cpp檔案中,不可以訪問靜態全域性變數,即使在本檔案使用extern宣告也不行
	//cout<<"static :"<<static_test<<endl;
	//如果靜態變數在其他.cpp檔案中,可以訪問非靜態全域性變數,但是要在本檔案使用extern宣告
	cout<<"non-static: "<<nonstatic_test<<endl;

	system("pause");
	return 0;
}
不新增extern時,靜態全域性變數為未定義,而即使新增extern宣告也會報錯: C++Test2.obj : error LNK2001: 無法解析的外部符號 "int static_test" ([email protected]@3HA)
1>: fatal error LNK1120: 1 個無法解析的外部命令
關於靜態全域性變數,有下面三點要注意: 1)靜態全域性變數如果未初始化,會被預設初始化為0,而非靜態全域性變數,注意是全域性變數,也是初值為0。(非靜態非全域性變數如果未初始化在VS中會直接報錯的) 2)靜態全域性變數在全域性資料區非配記憶體,所以變數的生存期是整個程式的執行週期。(區域性靜態變數的生存期也是整個程式執行週期) 3)靜態全域性變數在變數宣告的檔案是可見的,但是在其他檔案中是不可見的。 關於全域性變數: 如果我們將全域性變數直接放在標頭檔案中,變數會隨著標頭檔案的引入,引入到各個檔案中。有時候這是我們不想看到的,所以另一種方法是將全域性變數放在.cpp檔案中,這樣,全域性變數就不會隨著.h檔案到處引入,不是全域性可見。但是,這樣這個變數仍然是全域性變數,要想在另外的檔案中使用這個變數,就要在這個檔案中使用extern關鍵字宣告一下。如果不宣告,就會出現變數未宣告的情況。如果直接在這個變數再定義一個同名的變數,就會出現衝定義的情況,這也是我們不想看到的,如果全域性變數僅僅在本檔案中有用,那麼不如直接使用靜態全域性變數。

2.靜態區域性變數

區域性變數,即儲存在棧空間的變數,我們在呼叫函式時,變數初始化,而函式呼叫結束時,區域性變數的生存期就結束了,進而被銷燬。而有時候我們需要對兩次呼叫函式之間的變數進行儲存,最簡單的想法就是使用一個全域性變數,但是這個變數就已經不屬於函式本身,而是全域性可見,不符合區域性性原理,給維護帶來了不便。而靜態區域性變數剛好可以解決這個問題。靜態區域性變數儲存在全域性資料區,不會因函式結束而銷燬,並且在其他函式看來,靜態區域性變數是不可見的,剛好滿足了我們的需求! 下面看一個例子:
// C++Test.cpp : 定義控制檯應用程式的入口點。
//

#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
using namespace std;


void TestFunc()
{
	//定義一個靜態區域性變數,但是這個變數僅僅在第一次的時候初始化,再次呼叫時不會再初始化
	static int static_num = 10;
	//但是普通區域性變數,每次都會初始化
	int nonstatic_num = 10;
	static_num++;
	nonstatic_num++;
	cout<<"non_static: "<<nonstatic_num<<"  static :"<<static_num<<endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
	//呼叫10次該函式
	for(int i = 0; i < 10; i++)
		TestFunc();

	system("pause");
	return 0;
}

結果:

non_static: 11  static :11
non_static: 11  static :12
non_static: 11  static :13
non_static: 11  static :14
non_static: 11  static :15
non_static: 11  static :16
non_static: 11  static :17
non_static: 11  static :18
non_static: 11  static :19
non_static: 11  static :20
請按任意鍵繼續. . .

從上面的結果我們看出,函式被呼叫了10次,非靜態變數每次都被初始化,因而結果沒變。而靜態變數卻只被初始化了一次,因而每次結果都比上一次大1。

關於區域性靜態變數要注意的幾點:

1)區域性靜態變數也在全域性資料區分配記憶體,不會因為函式呼叫結束而銷燬。

2)區域性靜態變數在首次呼叫到該變數的時候進行初始化,之後再次呼叫時不會再進行初始化。並且區域性靜態變數一般就在宣告處初始化,如果未顯示初始化,則預設初始化為0

3)區域性靜態變數的生命週期為宣告時到程式結束,但是它的作用域卻是區域性的,僅僅在該函式內,不會破壞區域性性原理。

3.靜態函式

函式預設是全域性可見的,而如果我們希望某個函式只在本檔案中可見,那麼可以將它宣告為靜態函式。這一點與靜態全域性變數差不多。 一個例子:
//StaticTest.h
#include <iostream>
using namespace std;


void NormalFuncTest();

static void StaticFuncTest();
//StaticTest.cpp
#include "stdafx.h"
#include "StaticTest.h"


void NormalFuncTest()
{
	cout<<"Normal Func!"<<endl;	
}

static void StaticFuncTest()
{
	cout<<"Static Func!"<<endl;
}

// C++Test.cpp : 定義控制檯應用程式的入口點。
//main函式

#include "stdafx.h"
#include <iostream>
#include "StaticTest.h"
using namespace std;


int _tmain(int argc, _TCHAR* argv[])
{
	NormalFuncTest();
	StaticFuncTest();

	system("pause");
	return 0;
}
這個例子中有兩個函式,都定義在另一個檔案中,一個為普通函式,另一個為static函式。編譯一下,會出現如下錯誤:
\vs2012\vs12\vc\include\xlocnum(155): error C2129: 靜態函式“void StaticFuncTest(void)”已宣告但未定義
就是說,編譯器只看到了.h檔案中的宣告,但是看不到.cpp檔案中的實現。這樣,static的目的就達到啦!但是,如果將函式的實現放到了.h中,那麼,不管是不是靜態的,都是可以使用的。

二.面向物件程式設計中的Static關鍵字

1.靜態資料成員

在類中,成員也可以宣告為靜態資料成員,而在面向物件程式設計中,static關鍵字又有了新的功能。 先來一個例子:
// C++Test.cpp : 定義控制檯應用程式的入口點。
//

#include "stdafx.h"
#include <iostream>
using namespace std;


class StaticTest
{
private:
	//此處為宣告,宣告一個靜態成員變數
	static int count;
	int id;
public:
	StaticTest(int i): id(i)
	{
		count++;
	}

	void Show()
	{
		cout<<"ID: "<<id<<endl;
	}

	static void ShowCount()
	{
		cout<<"Count: "<<count<<endl;
	}
};

//在類外定義並初始化靜態成員變數,由於定義時需要分配空間,所以不能在類宣告中定義
int StaticTest::count = 0;


int _tmain(int argc, _TCHAR* argv[])
{

	StaticTest test1(1);
	StaticTest test2(2);
	test1.Show();
	test2.Show();
	StaticTest::ShowCount();

	system("pause");
	return 0;
}

結果: ID: 1
ID: 2
Count: 2
請按任意鍵繼續. . .
關於靜態成員變數有下面幾點: 1)靜態成員變數在一個類中只有一份,由該類所有的物件所共享,靜態資料成員只分配一次記憶體。而非靜態成員變數則是每個物件都有一份自己的拷貝。 2)靜態成員變數遵循public,private,protected的訪問規則 3)靜態資料成員在全域性資料區分配記憶體,屬於本類所有物件共享,但是它不屬於任何一個物件,所以即使沒有產生物件時也可以使用靜態成員變數。 4)靜態成員變數的初始化比較特殊,不能直接像普通成員變數那樣在類中給初值,更不能像非成員變數那樣直接初始化,靜態成員變數需要在類的定義中宣告,然後再類外面,用<型別><類名>::<變數名> = <值>的格式來初始化。如上面的例子中:int StaticTest::count = 0; 5)訪問靜態成員變數的方式也有兩種,一種是與普通成員變數的訪問方式一樣,<物件名>.<靜態資料成員>。另一種是靜態成員變數特有的方式<類名>::<靜態資料成員>

2.靜態成員函式

還是上面的那個例子,加了一部分功能:

// C++Test.cpp : 定義控制檯應用程式的入口點。
//

#include "stdafx.h"
#include <iostream>
using namespace std;


class StaticTest
{
private:
	//此處為宣告,宣告一個靜態成員變數
	static int count;
	int id;
public:
	StaticTest(int i): id(i)
	{
		count++;
	}

	void Show()
	{
		//但是非靜態成員函式可以訪問靜態成員函式和變數
		cout<<"ID: "<<id<<"  Count: "<<count<<endl;
	}

	static void ShowCount()
	{
		//靜態成員函式不能訪問非靜態的成員,非靜態成員函式也不行!
		//cout<<"ID: "<<id<<endl;     error C2597: 對非靜態成員“StaticTest::id”的非法引用
		//Show();:                    error C2352: “StaticTest::Show”: 非靜態成員函式的非法呼叫
		cout<<"Count: "<<count<<endl;
	}
};

//在類外定義並初始化靜態成員變數,由於定義時需要分配空間,所以不能在類宣告中定義
int StaticTest::count = 0;


int _tmain(int argc, _TCHAR* argv[])
{

	StaticTest test1(1);
	StaticTest test2(2);
	test1.Show();
	test2.Show();
	StaticTest::ShowCount();

	system("pause");
	return 0;
}

結果:

ID: 1  Count: 2
ID: 2  Count: 2
Count: 2
請按任意鍵繼續. . .

關於靜態成員函式注意的地方:

1)靜態成員函式可以訪問靜態成員函式和靜態成員變數。但是靜態成員函式不能訪問普通成員變數和普通成員函式。(因為靜態成員函式沒有this指標,屬於共用)

2)非靜態成員函式可以訪問靜態成員變數和靜態成員函式。

3)定義在類外的靜態成員函式不能加static,宣告時加個static即可,定義時和普通成員函式相同。

4)靜態成員函式與靜態成員變數的呼叫規則一致,都不需要有物件就能呼叫。可以使用正常方法,也可以使用類名::呼叫。


相關推薦

C++那些細節--static關鍵字

static也是我們經常用到的關鍵字,關於static有很多用法,而且在面向過程和麵向物件程式設計中,static有著不同的意義。之前總是記不住,於是,本人強迫症又發作了,一定要搞懂它!!! 一.面向過程程式設計中的static關鍵字 1.靜態全域性變數 靜態全域性變數:

C++那些細節--inline關鍵字

Even with __forceinline, the compiler cannot inline code in all circumstances. The compiler cannot inline a function if:(1)The function or its caller is co

C++那些細節--typedef關鍵字

一.簡介 關於typedef關鍵字,以前剛剛學C語言的時候,用它來重定義結構體別名。之後的話就是在用函式指標的時候用過一些,然而並不知道這個還有什麼用處。今天花點時間總結一下typedef的細節。 在計算機程式語言中用來為複雜的宣告定義簡單的別名,與巨集定義有些差異。簡單

C++中的static關鍵字的總結(轉)

blank protected .com 如果 發現 內部實現 屬於 out 服務  C++的static有兩種用法:面向過程程序設計中的static和面向對象程序設計中的static。前者應用於普通變量和函數,不涉及類;後者主要說明static在類中的作用。 1.面向過程

C++中的static關鍵字

不能 get () turn out nbsp 所有 說明 靜態 類中的成員可分為普通成員和靜態成員,函數可分為普通函數和靜態函數。普通成員只能是每個對象獨自擁有,而靜態成員則是類的所有對象所共有的。靜態成員函數中,只能調用靜態成員變量,不能調用普通成員變量。 例如:

C語言中static關鍵字的作用

編譯 size lac 所有 指針 變量 運行時 http 多個 在C語言中static的作用如下 第一、在修飾變量的時候,static修飾的靜態局部變量只執行一次,而且延長了局部變量的生命周期,直到程序運行結束以後才釋放。 第二、static修飾全局變量的時候,這個全局變

【轉】c++中的static關鍵字總結

個人總結: static會隱藏全域性變數和全域性函式可見範圍,使其盡在定義檔案中可見; static會改變區域性變數生存週期,在程式中一直存在,而不僅僅在區域性變數定義的函式中; static會改變類的成員變數的生存週期,在程式中一直存在; static會修改函式的使用方

C語言中static關鍵字的作用詳解

在C語言中,static的字面意思很容易把我們匯入歧途,其實它的作用有三條。 (1)先來介紹它的第一條也是最重要的一條:隱藏。 當我們同時編譯多個檔案時,所有未加static字首的全域性變數和函式都具有全域性可見性。為理解這句話,我舉例來說明。我們要同時編譯兩個原始檔,一個是a.c,另一個是

C語音中,static 關鍵字的用法.兩個疑問

static修飾全域性變數只能在本檔案中使用。如果一個全域性變數,它既可以在本原始檔中被訪問到,也可以在同一個工程的其它原始檔中被訪問就需要用到extern. // ------ file: m.c #include <iostream> extern void

c語言中static關鍵字用法詳解

概述 static關鍵字在c語言中比較常用,使用恰當能夠大大提高程式的模組化特性,有利於擴充套件和維護。 但是對於c語言初學者,static由於使用靈活,並不容易掌握。本文就static在c語言中的應用進行總結,供參考使用。錯漏之處,請不吝指正。 在程

C++那些細節--32位64位資料型別的區別

Platform SDK: 64-bit Windows Programming Abstract Data Models Every application and every operating system has an abstract data model. Many applications do

C++那些細節--拷貝建構函式

關於C++拷貝建構函式,一直不是很明白,於是強迫症又發作,一定要搞懂它!! 另外附上參考的文章(這位大神寫得實在太棒了,讓我瞬間搞懂了這個糾結了很久的問題): 一.簡介: 拷貝建構函式,又稱複製建構函式,是一種特殊的建構函式,它由編譯器呼叫來完成一些基於同一類的其他物件

C/C++中使用static關鍵字定義或宣告靜態物件

在C/C++中使用static關鍵字來定義或宣告靜態物件,主要有以下的應用場景: (1)static修飾區域性物件,使其成為靜態區域性物件 將一個函式中定義的變數宣告為static物件,那麼在函式被多

c++中的 static 關鍵字

注:若沒有特指是 靜態成員時,預設都是普通成員; 1 類中的普通成員   類中的成員變數 和 成員函式 是分開儲存的。其中,     1)每個物件都有獨立的成員變數;成員變數可以儲存在 棧空間、堆空間、全域性資料區;     2)所有物件共享類的成員函式;成員函式 只能儲存在 程式碼段; 2 類中的靜態成員(

C++中static關鍵字作用總結

可見性 apple 局部變量 內存 父類靜態 初始化 ati 退出 變量存儲 1.先來介紹它的第一條也是最重要的一條:隱藏。(static函數,static變量均可) 當同時編譯多個文件時,所有未加static前綴的全局變量和函數都具有全局可見性。舉例來說明。同時編譯兩個源

淺析C++中static關鍵字

參數 extern 函數 iostream 出現 har 兩個 什麽 註意事項 C++的static有兩種用法:面向過程程序設計中的static和面向對象程序設計中的static。前者應用於普通變量和函數,不涉及類;後者主要說明static在類中的作用。 一、面向過程設計中

C ------ static 關鍵字的作用

不同 普通 範圍 oid 修飾 數據 error -- 關鍵字 首先要理解生存周期與作用域的區別: 生存周期: 變量從定義到銷毀的時間範圍。存放在全局數據區的變量的生存周期存在於整個程序運行期間,而存放在棧中的數據則隨著函數等的作用域結束導致出棧而銷毀,除了靜態變量之外的局

C++ static關鍵字作用

esp 接收 name names 分配 c++ spa 成員函數 它的 (1)函數體內static變量的作用範圍為該函數體,不同於auto變量,該變量的內存只被分配一次,因此其值在下次調用時仍維持上次的值; (2)在模塊內的static全局變量可以被模塊內所用函數訪問,

C語言學習及應用筆記之二:C語言static關鍵字及其使用

static關鍵字 可能 語言 需要 c語言 UNC function 不必要 能夠   C語言有很多關鍵字,大多關鍵字使用起來是很明確的,但有一些關鍵字卻要相對復雜一些。我們這裏要說明的static關鍵字就是如此,它的功能很強大,相應的使用也就更復雜。   一般來說sta

c到cpp對static 關鍵字的總結 需要整理下!!!!!!!!!!!!!!!!!!!!!!

之間 所在 結束 初始 程序 全局函數 代碼區 16px 類對象 一個完整的程序,在內存中的分布情況如下:  具體分布圖 自己看書去!!!!!1.棧區: 由編譯器自動分配釋放,像局部變量,函數參數,都是在棧區。會隨著作用於退出而釋放空間。3.堆區:程序員分配並釋放的