原創 C++作用域 (一)


1概述

在所有的計算機程序中,一個基本的目標是操作一些數據,然后獲得一些結果。為了操作這些數據,需要為這些數據分配一段內存,我們可以將這段內存稱為變量。為了方便操作,以及程序可讀性方面的考慮,需要使用一個有意義的名稱來引用這段內存,這個名稱就是變量名。

將名稱和一段內存關聯起來的工作可以分成兩個階段來進行,分別是變量的聲明和定義。在變量聲明的時候,只是引入了一個名稱,該名稱並沒有和一段特定的內存關聯。也就是說,在聲明變量的時候,只是引入了一個助記符,並沒有執行內存分配。在定義變量的時候,將前面聲明過程中引入的名稱關聯到了一段特定的內存,內存的大小由變量的類型決定。也就是說,在定義變量的時候,真正執行了內存分配。在有的情況下,變量的聲明和定義是需要分開進行的,如:全局變量的聲明和定義,可以在多個文件中使用該變量;而在某些情況下,使用一個語句就可以完成變量的聲明和定義,如:局部變量的聲明和定義。只需要在一個文件中使用該變量。

在C++程序中,當聲明並定義了一個變量以后,需要關注如下兩個問題:

  1. 由聲明引入的變量名可以用在什么地方,如何進行名字解析;
  2. 由定義分配的內存的生命周期是多少。

為了解決這兩個問題,就需要引入作用域的概念。作用域是C++程序中的一段區域,一般用正反兩個花括號來界定它的范圍。在同一個作用域范圍內,一個名稱只能唯一關聯到一個實體,這個實體可以是變量,函數,類型,模版等。也就是說,在同一作用域范圍內,不同的實體必須對應不同的名稱,絕對不允許出現兩個不同的實體對應同一個相同的名稱的情況。一個名稱可以和不同作用域中的不同實體相對應。也就是說,對於同一個名稱,在不同的作用域中可以重復使用。

在本文的后續部分,將對各種類型的作用域進行描述,並且介紹在作用域中進行名字解析的規則。

2作用域的分類

2.1概述

我們可以將整個C++程序(在程序中包括各種類型,函數,模版,變量等,並且分布在很多個*.cpp文件中)看成一個很大的整體區域。為了方便對C++程序中已經定義的各種類型,函數,模版,變量的管理,可以把這片大的區域划分成一片片小的命名區段。然后根據各個類型,函數,模版,變量的功能以及用途等,再把這些類型,函數,模版,變量等分別放置在不同的區段中。這些小的區段叫做作用域,C++程序支持四種形式的作用域,分別是:名字空間作用域,類域,局部作用域,語句作用域。

名字空間作用域就是程序員利用名字空間定義在C++程序中划分出來的一塊比較大的程序區段。在該程序區段內部,可以定義類型,函數,模版,變量。名字空間作用域可以跨越多個*.cpp文件而存在。在名字空間作用域內部還可以繼續定義其他的名字空間作用域,也就是說,名字空間作用域是可以互相嵌套的。

全局作用域是C++程序最外層的名字空間作用域,也是最大的名字空間作用域。全局作用域天然存在於C++程序中,它不需要由程序員人為地定義。在全局作用域內部,可以包含其他的,由程序員定義的名字空間作用域,以及沒有包含在其他名字空間作用域中的類型,函數,模版,變量。在全局作用域中定義的變量是全局變量,在全局作用域中定義的函數是全局函數。

在C++程序中,每定義一個類就會引入一個類域。類體所包含的范圍就是類域的范圍,在類中定義的所有成員都屬於該類域。類域位於名字空間作用域內部,該名字空間作用域可能是全局作用域,也可能是用戶定義的名字空間作用域。

每一個函數體內部都是一個局部作用域。該作用域起始於函數體的左花括號“{”,結束於函數體的右花括號“}”。每一個函數都有一個獨立的局部作用域。在局部作用域內定義的變量都是局部變量。

在C++程序中,當要求使用單個語句,但程序邏輯卻需要不止一個單個語句的時候,我們可以使用復合語句。復合語句通常被稱為塊,是用花括號括起來的一些單個語句的集合。在復合語句花括號內部的區段也屬於局部作用域。

有些語句存在控制結構,並且允許在控制結構中定義變量。如:

 

示例一:

for ( int K = 0; K < 100;K++ )

  cout << K;     //該行語句屬於語句作用域范圍,K僅在這一行有效。

示例二:

for (int K = 0; K < 100;K++)

{

   … //其他代碼

   Cout << k;   //花括號內部是復合語句,都屬於語句作用域。K在整個花括號內有效。

   … //其他代碼

}

 

    從控制語句的開始到控制語句結束這一段區域被稱為語句作用域。在該控制結構中定義的變量,僅在該語句作用域內有效。如:示例二中,K在花括號內有效,或者示例一中,僅在語句“cout << K;”中有效。語句作用域是最小的作用域。

全局作用域,名字空間作用域,類域,局部作用域,語句作用域之間的關系如下圖所示:

 

從上圖可以看出,在全局作用域中,定義了兩個名字空間H和K。名字空間H又分別位於兩個CPP文件A和B中。由此可見,名字空間作用域是可以跨越CPP文件的。在名字空間K中,除了定義了類型外,又定義了一個名字空間N,所以說,名字空間之間是可以互相嵌套的。另外,在名字空間中可以定義類,函數,變量,模版等。

在全局作用域中,除了定義的名字空間H和K外,又定義了一個類D,以及全局函數,全局變量和模版。在類D中,定義了一些成員函數,因此引出了局部作用域。在局部作用域中,如果存在控制語句,就會存在語句作用域。

在各種作用域中定義的變量或對象,其生命周期從該變量被定義開始,直到該作用域結束。如:在全局作用域中定義的變量,其生命周期是整個程序的生命周期,程序運行結束,該變量被釋放;在局部作用域中定義的變量,其生命周期是從定義該變量開始,直到該函數執行完畢。

2.2名字空間作用域

2.2.1名字空間的意義

使用名字空間可以在一定程度上解決命名沖突的問題。假設沒有名字空間,那么在C++程序中,所有的實體,如:函數,類型,變量,模版等,都必須被放置在全局域中作為全局實體而出現。在全局域中,這些實體必須具有唯一的名稱,不允許存在多個實體同名的情況。因此,當在全局域中引入一些第三方開發的類庫的時候,必須要保證第三方類庫中命名的實體與全局域中命名的實體在命名方面不沖突。但是,這是很難保證的。為了解決這個問題,就引入了名字空間的概念。

第三方開發方在開發類庫的時候,可以首先聲明一個名字空間,每一個用戶聲明的名稱空間都代表一個不同的名字空間域。在該名字空間中,可以包含嵌套其他的名稱空間,以及函數,類型,變量,模版等的聲明和定義。在該名稱空間內部聲明的實體被稱為名稱空間成員。用戶在名字空間中聲明的每個實體的名字必須是唯一的,不允許重名。因為在不同用戶聲明的名字空間中引入了不同的域,所以在這些由不同用戶聲明的名字空間中可以使用相同的名稱。通過這種方式解決了命名沖突的問題。

在使用名字空間中的成員的時候,名字空間成員的名字會自動與該名字空間重合,或者說被其限定修飾。如:在名字空間A中聲明的類B,它的名字是:A::B。

2.2.2名字空間的定義

用戶聲明的名字空間以namespace關鍵字開頭,后面是名字空間的名稱。名字空間的范圍以花括號界定,具體的格式如下:

namespace mySpace //mySpace是名字空間的名稱

{

   Class myClass { … }; //類定義

   Int myFunction(int para1,int para2); //函數的聲明

   Extern double myVar; //變量的聲明

}

    在上面的示例中,聲明了一個名稱為mySpace的名字空間,該名字空間的作用域由花括號界定,在花括號內部的部分都屬於該名字空間的作用域。在該名字空間中,定義了一個類:myClass,聲明了一個函數:myFunction,以及一個變量myVar。它們都是該名字空間的成員。

   

用戶聲明的名字空間可以位於全局作用域中,也可以位於其他的名字空間的作用域中。在當前的作用域中,名字空間的名稱是唯一的,不能與其類型的實體重名。

在同一個作用域中,可以多次聲明相同名稱的名字空間。在這種情況下,將會實現名字空間的累加。比如,A.h頭文件和A.cpp源文件都位於全局作用域中,在這兩個文件中分別聲明如下的名字空間:

A. h文件的代碼實現:

namespace mySpace //在這里實現了函數和變量的聲明,屬於接口部分。

{

   Int AddData (int para1,int para2); //函數的聲明

   Extern double myVar;  //變量的聲明

}

B.cpp文件的代碼實現:

Include “A.h”

namespace mySpace // 在這里實現了函數和變量的定義,屬於實現部分。

{

   Int AddData(int Para1,int Para2) //函數的定義

   {

      Return Para1+Para2;

   }

 

    Double myVar = 3.14;  //變量的定義,並初始化。

}

在這里,存在這樣一個規則:在同一個作用域中,如果新聲明的一個名字空間的名稱與前面聲明過的名字空間的名稱同名,那么這個后聲明的名字空間就是前面聲明的名字空間的累加,這兩部分內容屬於同一個名字空間;如果新聲明的這個名字空間不與當前作用域中任何名字空間同名,那么就會定義一個新的名字空間。

在上面的示例中,A.h和A.cpp文件位於全局作用域中。在全局作用域中,兩次聲明的名字空間具有相同的名稱:mySpace。因此,認為這兩次聲明的名字空間屬於同一個名字空間。

通過對上面所描述的規則的使用,在程序設計的時候,可以根據需要,將名字空間的聲明拆分成若干個部分來實現,只要這幾個部分的聲明都在同一個作用域中即可。這個規則的一個典型應用就是:實現接口和具體實現的分離。

在上面的示例中,我們將函數AddData和變量myVar的聲明放在了A.h頭文件中,而將它們的定義放在了另外一個A.cpp的源文件中。 A.h頭文件實現的是函數庫的接口的,而A.cpp文件中的內容則是針對接口的實現。因此,在程序設計和開發的時候,這兩部分內容可以分別由不同的人在不同的時間實現。通過這種方式,實現了接口和具體實現分離的原則。

 

2.2.3名字空間成員的定義

當定義了名字空間以后,就可以想名字空間中添加成員。這些被添加的成員可以是:類型,函數,變量,模版等。可以通過兩種方式向名字空間中添加成員。

第一種方式是:在定義名字空間的同時,在名字空間的花括號內直接完成名字空間成員的定義。也就是說,無論名字空間的定義是采用累加的形式,還是該名字空間分布在多個物理文件中,名字空間成員的聲明和定義都在名字空間內部進行。具體示例如下:

方式一:在名字空間中直接完成成員的定義。成員的定義不在划分為聲明和定義兩部分。

Namespace mySpace

{

   Double myVar = 3.14;

   Int myFunction(int Para1)

   {

       Return Para1*10;

   }

}

方式二:在名字空間中先完成成員的聲明,然后采用名字空間累加的方式,在其他部分完成成員的定義。這個“其他部分”,可以是其他的物理文件,也可以是同一個物理文件。

Namespace mySpace

{

Extern double myVar;

Int myFunction(int Para1);

}

 

Namespace mySpace

{

Double myVar = 3.14;

Int myFunction(int Para1)

{

   Return Para1*10;

}

}

在上面的代碼中,在定義了名字空間的同時(無論是采用累加方式,還是一次性完成),在名字空間內部完成了函數myFunction和變量myVar的定義。名字空間的定義和名字空間成員的定義同步完成。

第二種方式是:在定義名字空間的時候,僅僅在名字空間中完成對名字空間成員的聲明,而名字空間成員的定義在名字空間之外被實現。具體代碼如下:

//首先在一個文件中完成名字空間的定義,以及名字空間成員的聲明。一般情況下,該文件為頭文件(A.h)。

Namespace mySpace

{

Class myClass {….};//聲明一個類型

myClass myFunction(myClass Para1);//聲明一個函數,該函數返回myClass類型,並以myClass類型為參數。

}

在上面的代碼中,完成了對名字空間mySpace的定義,同時在名字空間內部,完成了類myClass的定義,以及對函數myFunction的聲明。接下來需要在其他地方,名字空間以外,完成對名字空間成員myFunction函數的定義。具體代碼如下:

//實現函數myFunction定義的位置,可以是另外一個文件,一般為cpp文件,但是也可以在原來的頭文件中(一般不會這么干)。

#include “A.h”

mySpace::myClass mySpace::myFunction(myClass Para1)

{

    //下面完成函數的具體實現。

   …

}

在上面的代碼中,我們可以看到兩處差異。一處是函數的返回值類型,myClass被名字空間mySpace限定修飾了;而在函數的參數類型處,myClass直接使用,沒有被名字空間mySpace限定修飾。

這里存在這樣一個規則:在函數的限定修飾名稱“mySpace::myFunction”之后,直到方括號結束的區域都屬於mySpace名字空間的作用域范圍。也就是上面代碼中的紅色部分。

也就是說名字空間的作用域可能會有兩部分組成,在大多數情況下,名字空間的作用域是由定義名字空間的時候,名字空間體的花括號界定的。但是,當在名字空間之外定義名稱空間的成員的時候,在名字空間成員的限定修飾名之后直到結束花括號(” }”),或者分號(;)的部分都屬於該名字空間作用域范圍。

因此,在上面的代碼中,參數的類型不需要被限定修飾,因為那個區域是屬於名字空間作用域內的;而函數的返回類型必須要被限定修飾,因為那個區域不屬於名字空間的作用域內。

另外還需要注意,在名字空間之外實現名字空間成員的定義的時候,要有一個前提,那就是:名字空間成員的聲明必須在名字空間之內實現。

2.2.4名字空間成員的使用

在C++程序中,使用名字空間的方式封裝一些函數庫或者類庫的時候,一般情況下,通常的做法是這樣的:首先在一個頭文件中定義一個名字空間,然后在該名字空間的定義中聲明所有的名字空間成員,如:函數,類型,變量等。之后將這個頭文件引入到一個cpp文件中,並且在這個cpp文件中實現所有名字空間成員的定義。具體示例如下:

-----------------A.h------------------------------//頭文件名稱

namespace myCPlusPlusFunctionsV1.0

{

     Class myClass { …//類成員的聲明 }; //定義一個類型

     Extern double myVar; //聲明變量

     Void DealClass(myClass*); //聲明函數

}

-----------------A.cpp--------------------------//源文件

#include “A.h”

Namespace myCPlusPlusFunctionsV1.0

{

myClass:: myClass() { … // myClass構造函數的實現}

//其他myClass類成員的定義。

double myVar = 3.14;//變量的定義

void DealClass(myClass*pClass)

{

   …//函數的具體實現。

}

}

 

在使用這些函數庫或者類庫的時候,首先需要將這個定義了該名字空間的頭文件引入,然后開始使用該名字空間中的一些成員。在使用名字空間成員的時候,有三種方式:

第一種方式:域操作符方式。通過域操作符加名字空間名稱的方式對名字空間成員名進行限定修飾。具體代碼如下:

------------------otherCPlusPlusFile.cpp-------------------------

#include “A.h”

Void main()

{

   myCPlusPlusFunctionsV1.0::myClass *pClass = new myCPlusPlusFunctionsV1.0::myClass;

   myCPlusPlusFunctionsV1.01::DealClass(pClass);

}

在上面的代碼中,“::”是域操作符。名字空間成員的聲明被隱藏在名字空間之中,所以,名稱空間的成員名稱不會與當前作用域中的對象實體名稱產生沖突。在使用名字空間成員的時候,可以使用名字空間名+域操作符+名字空間成員名稱的方式將名字空間成員引入到當前的作用域中。否則,在當前作用域中,編譯器不會找到名字空間的成員。

域操作符也可以被用來引用全局作用域的成員。因為全局作用域沒有名稱,所以使用如下的符號:

 ::member_name

指向全局名字空間的成員。當全局名字空間成員的名稱被局部作用域中的名字隱藏的時候,但又需要在局部作用域中使用全局成員的時候,就可以使用這種引用方式。

在上面的示例中,名字空間的名稱“myCPlusPlusFunctionsV1.0”比較長,在使用的時候,可能會不方便,因此,C++在處理這個問題的時候,引入了名字空間別名的概念。

    所謂名字空間別名就是為已經定義的名字空間取一個其他的、替代性的名稱,一幫情況下,這個名稱是簡短的,容易記憶的。具體使用方式如下:

 

------------------otherCPlusPlusFile.cpp-------------------------

#include “A.h”

Namespace myC++ = myCPlusPlusFunctionsV1.0;

Void main()

{

   myC++::myClass *pClass = new myC++::myClass;

   myC++::DealClass(pClass);

}

在上面的代碼中,為名字空間“myCPlusPlusFunctionsV1.0”定義了一個別名“myC++”。之后在引用該名字空間成員的時候,就可以使用該別名。

定義名字空間別名的格式是:以關鍵字namespace開頭,后跟名字空間的別名,並且等於前面定義好的名字空間的名稱。

第二種方式:使用using 聲明,一次引入一個名字空間成員。

Using 聲明的作用是:使一個名字空間成員在當前作用域中可見,可見的范圍是從using聲明的語句開始,直到當前作用域結束。如果在using聲明語句之后,在當前作用域中又嵌套了其他的作用域,那么using聲明在當前作用域中的嵌套作用域中也同樣有效。

Using聲明以關鍵字using開頭,后跟名字空間的成員名稱。該成員名稱必須是名字空間名稱+域操作符+名字空間成員名稱形式的限定修飾名稱。具體代碼如下:

//名字空間的定義

Namespace mySpace

{

Int myFunction(int Para)//在名字空間中定義了一個函數

{

     Return Para*10;

}

}

//在全局作用域中使用using聲明,將名字空間成員名引入當前作用域。

Using mySpace::myFunction;

//開始使用名字空間的成員

Void main()

{

   //也可以在此位置使用using聲明,即在局部作用域使用using聲明。

   myFunction(10);//使用名字空間的成員。因為使用了using聲明,所以不需要使用限定修飾的形式。名稱myFunction從using聲明開始,直到當前作用域結束。

}

在上面的代碼中,首先定義了一個名字空間,並在名字空間中定義了一個函數。然后在全局作用域中使用了using聲明。之后,在main函數中使用名字空間的成員函數myFucntin。

可以在全局作用域,名字空間作用域,局部作用域中使用using聲明。在使用了using 聲明以后,一次只能從源名字空間向當前作用域中引入一個名字空間成員,但可以多次使用using聲明。如果該名字空間成員是函數,並且在該名字空間中具有多個重載,那么在使用using聲明的時候,所有的重載函數都會被引入到當前的作用域中。被引入的名字空間成員名只在當前作用域中有效,並且名稱唯一。這個被引入的名字空間成員名會隱藏當前作用域外圍作用域中的同名名稱,也會被當前作用域的嵌套作用域中的同名名稱隱藏。具體情況見如下代碼:

namespace mySpace

{

   Int myIntVar = 10;//定義一個整型變量。名字空間成員。

}

 

Int myIntVar = 100;//全局變量

Int main()

{

Using mySpace::myIntVar;//該using聲明隱藏了全局變量myIntVar。

Int k = 10;

K = k + myIntVar;//使用的是名字空間的成員變量,所以k的值等於20.

K = K + ::myIntVar;//這里使用的是全局變量,所以k的值等於110.

{

     Int myIntVar = 50;//在此語句作用域中聲明的變量隱藏了前面using聲明中引入的變量。

    Int a  = myIntVar ;//a = 50

    Int b  = ::myIntVar;//b = 100;

    Int C  = mySpace::myIntVar;//c = 10;

}

}

使用using聲明將名字空間的成員引入到當前作用域的時候,除了重載函數以外,被引入的成員名稱不能與當前作用域中定義的對象實體重名,否則會引起錯誤。

第三種方式:使用using 指示符,一次引入所有名字空間成員。

Using指示符以關鍵字using 開頭后跟關鍵字namespace,最后是名字空間的名稱。該名字空間的名稱必須在前面已經定義。其作用域從using指示符開始,直到當前作用域結束。使用using指示符以后,將會把名字空間中的所有成員引入到當前作用域。具體的代碼如下:

//定義名字空間

Namespace mySpace

{

Int myFunction(int Para)

{

   Return Para*10;

}

Int myVar = 100;

}

//使用using指示符,將名字空間的所有成員引入到當前作用域。目前是全局作用域。

Using namespace mySpace;

Void main()

{

Int k = myVar + 10;//使用using指示符以后,可以直接使用名字空間中的成員,就好像該//名字空間的成員在當前作用域中定義的一樣,不需要限定修飾。

myFunction(k);

}

在上面的代碼中,首先定義了一個名字空間mySpace,同時在名字空間中定義了一個函數myFunction,以及一個變量myVar。然后使用using指示符將該名字空間中的成員引入到了全局作用域中。之后,在main函數中使用名字空間的成員,使用的時候,不需要限定修飾,就好像使用當前名字空間中定義的成員一樣。

在當前作用域使用using指示符以后,被引用的名字空間將與當前的作用域合並,名字空間中的成員就好像在當前作用域被定義一樣。因此,在當前作用域中,不能定義與名稱空間成員重名的對象。否則會因此錯誤。

2.2.6 標准名字空間std

在名字空間的概念被提出之前,在C++中就已經存在了大量的庫函數。這些庫函數有的是標注C形式的,也有的是標准C++形式的。在聲明這些庫函數的時候,按照其功能和類別,它們被划分到很多不同的頭文件中,如:iostream.h,complox.h,stdio.h。當名字空間的概念被提出之后,這些庫函數被重新整理,將它們的聲明和定義放到了名稱空間名稱為std的名稱空間中。它們被稱為標准C++庫。

但是為了向前兼容以前實現的C++程序,在對這些庫函數進行整理的時候,創建了新的頭文件,並采用了新的命名規則,以區分原有的庫函數。具體的處理方式描述如下:

  1. 對於支持C++的頭文件,如:<iostream.h>,在被重新整理之后,它的名稱為<iostream>去掉了頭文件的擴展名。新的頭文件所包含的功能與舊頭文件基本相同,但是它們在std名字空間中;
  2. 對於支持C標准的頭文件,如:<stdio.h>,在被重新整理之后,它的名稱為<cstdio>,在名稱的前面加上了前綴字符“C”,並去掉擴展名。新的頭文件所包含的功能與舊的頭文件基本相同,但是它們在std名字空間中。
  3. 原有舊的C++標准頭文件,如<iostream.h>,依然被支持,它們不在名字空間std中;
  4. 原有舊的C標准頭文件,如<stdio.h>,依然被支持,它們不在名字空間std中。
      

具體情況如下圖所示:

 

在C++標准庫中,一共50個頭文件,10個分類,其中18個C庫功能。與宏相關的名稱在全局作用域中定義,其他的在名字空間std中被定義。

   按照分類,C++標准庫的詳細情況如下表所示:

C1. 標准庫中與語言支持功能相關的頭文件

頭文件

描        述

<cstddef>

定義宏NULL和offsetof,以及其他標准類型size_t和ptrdiff_t。與對應的標准C頭文件的區別是,NULL是C++空指針常量的補充定義,宏offsetof接受結構或者聯合類型參數,只要他們沒有成員指針類型的非靜態成員即可。

<limits>

提供與基本數據類型相關的定義。例如,對於每個數值數據類型,它定義了可以表示出來的最大值和最小值以及二進制數字的位數。

<climits>

提供與基本整數數據類型相關的C樣式定義。這些信息的C++樣式定義在<limits>中

<cfloat>

提供與基本浮點型數據類型相關的C樣式定義。這些信息的C++樣式定義在<limits>中

<cstdlib>

提供支持程序啟動和終止的宏和函數。這個頭文件還聲明了許多其他雜項函數,例如搜索和排序函數,從字符串轉換為數值等函數。它與對應的標准C頭文件stdlib.h不同,定義了abort(void)。abort()函數還有額外的功能,它不為靜態或自動對象調用析構函數,也不調用傳給atexit()函數的函數。它還定義了exit()函數的額外功能,可以釋放靜態對象,以注冊的逆序調用用atexit()注冊的函數。清除並關閉所有打開的C流,把控制權返回給主機環境。

<new>

支持動態內存分配

<typeinfo>

支持變量在運行期間的類型標識

<exception>

支持異常處理,這是處理程序中可能發生的錯誤的一種方式

<cstdarg>

支持接受數量可變的參數的函數。即在調用函數時,可以給函數傳送數量不等的數據項。它定義了宏va_arg、va_end、va_start以及va_list類型

<csetjmp>

為C樣式的非本地跳躍提供函數。這些函數在C++中不常用

<csignal>

為中斷處理提供C樣式支持

C2. 支持流輸入/輸出的頭文件

頭文件

描        述

<iostream>

支持標准流cin、cout、cerr和clog的輸入和輸出,它還支持多字節字符標准流wcin、wcout、wcerr和wclog。

<iomanip>

提供操縱程序,允許改變流的狀態,從而改變輸出的格式。

<ios>

定義iostream的基類

<istream>

為管理輸出流緩存區的輸入定義模板類

<ostream>

為管理輸出流緩存區的輸出定義模板類

<sstream>

支持字符串的流輸入輸出

<fstream>

支持文件的流輸入輸出

<iosfwd>

為輸入輸出對象提供向前的聲明

<streambuf>

支持流輸入和輸出的緩存

<cstdio>

為標准流提供C樣式的輸入和輸出

<cwchar>

支持多字節字符的C樣式輸入輸出

C3. 與診斷功能相關的頭文件

頭文件

描        述

<stdexcept>

定義標准異常。異常是處理錯誤的方式

<cassert>

定義斷言宏,用於檢查運行期間的情形

<cerrno>

支持C樣式的錯誤信息

C4. 定義工具函數的頭文件

頭文件

描        述

<utility>

定義重載的關系運算符,簡化關系運算符的寫入,它還定義了pair類型,該類型是一種模板類型,可以存儲一對值。這些功能在庫的其他地方使用

<functional>

定義了許多函數對象類型和支持函數對象的功能,函數對象是支持operator()()函數調用運算符的任意對象

<memory>

給容器、管理內存的函數和auto_ptr模板類定義標准內存分配器

<ctime>

支持系統時鍾函數

C5. 支持字符串處理的頭文件

頭文件

描        述

<string>

為字符串類型提供支持和定義,包括單字節字符串(由char組成)的string和多字節字符串(由wchar_t組成)

<cctype>

單字節字符類別

<cwctype>

多字節字符類別

<cstring>

為處理非空字節序列和內存塊提供函數。這不同於對應的標准C庫頭文件,幾個C樣式字符串的一般C庫函數被返回值為const和非const的函數對替代了

<cwchar>

為處理、執行I/O和轉換多字節字符序列提供函數,這不同於對應的標准C庫頭文件,幾個多字節C樣式字符串操作的一般C庫函數被返回值為const和非const的函數對替代了。

<cstdlib>

為把單字節字符串轉換為數值、在多字節字符和多字節字符串之間轉換提供函數

C6. 定義容器類的模板的頭文件

頭文件

描        述

<vector>

定義vector序列模板,這是一個大小可以重新設置的數組類型,比普通數組更安全、更靈活

<list>

定義list序列模板,這是一個序列的鏈表,常常在任意位置插入和刪除元素

<deque>

定義deque序列模板,支持在開始和結尾的高效插入和刪除操作

<queue>

為隊列(先進先出)數據結構定義序列適配器queue和priority_queue

<stack>

為堆棧(后進先出)數據結構定義序列適配器stack

<map>

map是一個關聯容器類型,允許根據鍵值是唯一的,且按照升序存儲。multimap類似於map,但鍵不是唯一的。

<set>

set是一個關聯容器類型,用於以升序方式存儲唯一值。multiset類似於set,但是值不必是唯一的。

<bitset>

為固定長度的位序列定義bitset模板,它可以看作固定長度的緊湊型bool數組

C7. 支持迭代器的頭文件

 

頭文件

描        述

<iterator>

給迭代器提供定義和支持

C8. 有關算法的頭文件

頭文件

描        述

<algorithm>

提供一組基於算法的函數,包括置換、排序、合並和搜索

<cstdlib>

聲明C標准庫函數bsearch()和qsort(),進行搜索和排序

<ciso646>

允許在代碼中使用and代替&&

C9. 有關數值操作的頭文件

頭文件

描        述

<complex>

支持復雜數值的定義和操作

<valarray>

支持數值矢量的操作

<numeric>

在數值序列上定義一組一般數學操作,例如accumulate和inner_product

<cmath>

這是C數學庫,其中還附加了重載函數,以支持C++約定

<cstdlib>

提供的函數可以提取整數的絕對值,對整數進行取余數操作

C10. 有關本地化的頭文件

頭文件

描        述

<locale>

提供的本地化包括字符類別、排序序列以及貨幣和日期表示。

<clocale>

對本地化提供C樣式支持

 

2.2.5名字空間的嵌套

在用戶聲明的名字空間中還可以繼續嵌套其他的名字空間,通過這種分層次的名字空間的結構可以改善函數庫的代碼組織結構。具體代碼如下:

Namespace myFirstSpace

{

Int myVar = 10;

Namespace mySecondSpace

{

   int dlVar = 314;

   Int myVar = 100;//它會隱藏外圍名字空間聲明的變量。

}

}

只要需要,名字空間的嵌套可以一直向下持續下去。在名字空間嵌套的時候,外圍名字空間聲明的變量可能會被里面嵌套的名字空間聲明的同名變量隱藏。在使用嵌套名字空間成員的時候,有三種方式,具體情況如下:

//第一種形式:限定修飾名稱形式

Int a = MyFirstSpace::mySecondSpace::dlVar;

//第二中形式:using聲明的形式:

Using myFirstSpace::mySecondSpace::dlVar;

Int a= dlVar;

//第三中形式:using指示符形式:

Using namespace myFirstSpace::mySecondSpace;

Int a = dlVar;

 

2.2.6未命名名字空間

使用未命名的名字空間,可以定義文件作用域。具有文件作用域的名字空間只在定義它的文件中有效,在其他文件中訪問不到該作用域。

未命名名字空間的定義格式如下:

----------------------------A.cpp--------------------------

Namespace

{

   Int a = 10;

   Void myFunction(int Para)

{

}

}

 

//使用未命名名字空間中的成員

Void main()

{

   myFunciton(a);//直接使用,不需要限定修飾。

}

    在使用未命名名字空間中的成員的時候,可以直接使用,不需要限定修飾。未命名名字空間中的成員只能在定義它的文件中使用,在其他文件中是無法訪問的。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM