C++入門基礎知識

1.命名空間

C++ Namespace 詳解
命名空間的定義格式爲:(取自C++標準文檔)

named-namespace-definition:       
            namespace identifier { namespace-body }
unnamed-namespace-definition:       
            namespace { namespace-body }
namespace-body:       
            declaration-seqopt

有名的命名空間:
namespace 命名空間名 {
聲明序列可選
}

無名的命名空間:
namespace {
聲明序列可選
}

所謂C++中的namespace,是指標識符的各種可見範圍。C++標準程序庫中的所有標識符都被定義於一個名爲std的namespace中。
一、< iostream >和< iostream.h >
  < iostream >和< iostream.h >是不一樣,前者沒有後綴,實際上,在你的編譯器include文件夾裏面可以看到,二者是兩個文件,打開文件就會發現,裏面的代碼是不一樣的。
  後綴爲.h的頭文件c++標準已經明確提出不支持了,早些的實現將標準庫功能定義在全局空間裏,聲明在帶.h後綴的頭文件裏,c++標準爲了 和C區別開,也爲了正確使用命名空間,規定頭文件不使用後綴.h。
  因此,當使用< iostream.h >時,相當於在c中調用庫函數,使用的是全局命名空間,也就是早期的c++實現;當使 用< iostream >的時候,該頭文件沒有定義全局命名空間,必須使用namespace std;這樣才能正確使用cout。
二、所謂namespace,是指標識符的各種可見範圍。
  C++標準程序庫中的所有標識符都被定義於一個名爲std的namespace中。
  由於namespace的概念,使用C++標準程序庫的任何標識符時,可以有三種選擇:
  1、直接指定標識符。例如std::ostream而不是ostream。完整語句如下: std::cout << std::hex << 3.4 << std::endl;
  2、使用using關鍵字。 using std::cout; using std::endl; 以上程序可以寫成 cout << std::hex << 3.4 << endl;
  3、最方便的就是使用using namespace std;
例如:

#include <iostream> 
#include <sstream> 
#include <string> 
using namespace std; 
//這樣命名空間std內定義的所有標識符都有效。就好像它們被聲明爲全局變量一樣。那麼以上語句可以如下寫: 
cout<< hex << 3.4 <<endl;

因爲標準庫非常的龐大,所程序員在選擇的類的名稱或函數名時就很有可能和標準庫中的某個名字相同。所以爲了避免這種情況所造成的名字衝突,就 把標準庫中的一切都被放在名字空間std中。但這又會帶來了一個新問題。無數原有的C++代碼都依賴於使用了多年的僞標準庫中的功能,他們都是在全局空間 下的。 所以就有了< iostream.h >和< iostream >等等這樣的頭文件,一個是爲了兼容以前的C++代碼,一 個是爲了支持新的標準。命名空間std封裝的是標準程序庫的名稱,標準程序庫爲了和以前的頭文件區別,一般不加”.h” 。

點擊瞭解更多命名空間詳解

2.C++基本的輸入輸出流

輸入和輸出是數據傳送的過程,數據如流水一樣從一處流向另一處。C++形象地將此過程稱爲流(stream)。C++的輸入輸出流是指由若干字節組成的字節序列,這些字節中的數據按順序從一個對象傳送到另一對象。流表示了信息從源到目的端的流動。在輸入操作時,字節流從輸入設備(如鍵盤、磁盤)流向內存,在輸出操作時,字節流從內存流向輸出設備(如屏幕、打印機、磁盤等)。流中的內容可以是ASCII字符、二進制形式的數據、圖形圖像、數字音頻視頻或其他形式的信息。

實際上,在內存中爲每一個數據流開闢一個內存緩衝區,用來存放流中的數據。當用cout和插入運算符“<<”向顯示器輸出數據時,先將這些數據送到程序中的輸出緩衝區保存,直到緩衝區滿了或遇到endl,就將緩衝區中的全部數據送到顯示器顯示出來。在輸入時,從鍵盤輸入的數據先放在鍵盤緩衝區中,當按回車鍵時,鍵盤緩衝區中的數據輸入到程序中的輸入緩衝區,形成cin流,然後用提取運算符“>>”從輸入緩衝區中提取數據送給程序中的有關變量。總之,流是與內存緩衝區相對應的,或者說,緩衝區中的數據就是流。

在C++中,輸入輸出流被定義爲類。C++的I/0庫中的類稱爲流類(streamclass)。用流類定義的對象稱爲流對象。

前面曾多次說明,cout和cin並不是C++語言中提供的語句,它們是iostream類的對象,在未學習類和對象時,在不致引起誤解的前提下,爲敘述方便,把它們稱爲cout語句和cin語句。正如C++並未提供賦值語句,只提供賦值表達式,在賦值表達式後面加分號就成了C++的語句,爲方便起見,我們習慣稱之爲賦值語句。又如,在C語言中常用printf和scanf進行輸出和輸入,printf和scanf是C語言庫函數中的輸入輸出函數,一般也習慣地將由printf和scanf函數構成的語句稱爲printf語句和scanf語句。在使用它們時,對其本來的概念要有準確的理解。

點擊查看C++輸入輸出流詳解

3.重載(C++爲什麼支持重載?)

1、首先,我們需要了解的是,在c中,要求在同一個作用域中,函數名唯一。就是不允許函數同名。
而在C++中,要求同一個作用域中函數簽名唯一。函數簽名是函數名+參數列表。就是說允許函數名相同但參數列表不同的函數存在。可見,函數重載跟返回類型沒什麼關係。
2、那麼爲什麼C++允許函數簽名唯一呢?
代碼段在被編譯器編譯的時候,會根據函數名生成函數的調用地址。
C編譯器編譯之後,函數名不變。
而C++編譯器編譯之後,函數名就會發生命名置換。比如說代碼中的函數是

int function(int a,int b,double c)  
    {  
        cout<<a<<b<<c<<endl;  
    }  

gcc編譯,命名置換後,會變成_Z8functioniid。
其中_Z是gcc編譯器的保留字,不同的編譯器,生成的保留字也會不一樣,8是函數名的字符數量,iid則是參數列表的縮寫。
經過這樣一個操作時候,即使是函數名相同,但只要參數列表不同,那麼編譯之後生成的函數名實際上是不同的。
3、需要注意的是,函數名會發生命名置換,同樣,函數調用時也會發生置換。比如說:

int main()  
    {  
        function(2,5,2.36);  
    }  

這時,如果在C++中發生調用,不會出現問題。可是,如果是在C中調用,那麼C的編譯器是找不到經過C++編譯器命名置換的函數地址的。因爲C編譯器沒有命名置換,他調用的還是function這個函數名。於是出現了extern "C"這個關鍵字是告訴C++編譯器不用命名替換,用C編譯器的方式去編譯。

extern "C"  
{  
    int function(int a,int b,double c)  
    {  
        cout<<a<<b<<c<<endl;  
    }  
    int main()  
    {  
        function(2,5,2.36);  
    }  
};  

這樣就不會出現問題了。

4.C++缺省參數

在C++中參數可以設置缺省值,設置了缺省值之後,這個參數在調用時可以省略。

注意:設置缺省值的參數只能是最後的幾個參數。也就是說某一個參數一旦設置了缺省值,其後而的參數也必須設置缺省值。例如:f()函數有3個參數,如果只設置第2個有缺省值,這就錯了。因爲調用時只輸入2個參數時,系統不知道究竟是第2個參數還是第3個參數。

參數缺省值舉例:

#include <iostream>
using namespace std;
int sum(int x=0, int y=100, int z=0) { return x+y+z; }
//int sum(int x, int y=100, int z=0) { ... }   //這是正確的
//int sum(int x, int y, int z=0) { ... }       //這也是正確的
//int plus(int x, int y=100, int z) { ... }    //這是錯誤的
int main ( )
{
    cout << sum() << endl;
    cout << sum(6) << endl;
    cout << sum(6, 10) << endl;
    cout << sum(6, 10, 20) << endl;
    return 0;
}

運行結果:
100
106
16
36

5.指針和引用(概念、使用方法、做參數、做返回值的作用,指針和引用的區別)

引用參數

從概念上講。指針從本質上講就是存放變量地址的一個變量,在邏輯上是獨立的,它可以被改變,包括其所指向的地址的改變和其指向的地址中所存放的數據的改變。

而引用是一個別名,它在邏輯上不是獨立的,它的存在具有依附性,所以引用必須在一開始就被初始化,而且其引用的對象在其整個生命週期中是不能被改變的(自始至終只能依附於同一個變量)。

在C++ 中,指針和引用經常用於函數的參數傳遞,然而,指針傳遞參數和引用傳遞參數是有本質上的不同的:

指針傳遞參數本質上是值傳遞的方式,它所傳遞的是一個地址值。值傳遞過程中,被調函數的形式參數作爲被調函數的局部變量處理,即在棧中開闢了內存空間以存放由主調函數放進來的實參的值,從而成爲了實參的一個副本。值傳遞的特點是被調函數對形式參數的任何操作都是作爲局部變量進行,不會影響主調函數的實參變量的值。(這裏是在說實參指針本身的地址值不會變)

而在引用傳遞過程中,被調函數的形式參數雖然也作爲局部變量在棧中開闢了內存空間,但是這時存放的是由主調函數放進來的實參變量的地址。被調函數對形參的任何操作都被處理成間接尋址,即通過棧中存放的地址訪問主調函數中的實參變量。正因爲如此,被調函數對形參做的任何操作都影響了主調函數中的實參變量。

引用傳遞和指針傳遞是不同的,雖然它們都是在被調函數棧空間上的一個局部變量,但是任何對於引用參數的處理都會通過一個間接尋址的方式操作到主調函數中的相關變量。而對於指針傳遞的參數,如果改變被調函數中的指針地址,它將影響不到主調函數的相關變量。如果想通過指針參數傳遞來改變主調函數中的相關變量,那就得使用指向指針的指針,或者指針引用。

引用返回值

引用返回值的概念與引用參數相似,下面通過幾個例子說明容易出錯的地方。

(1)int &max(int i, int j){//錯誤的用法,i和j都是局部變量

return i>j?i:j;

}

(2)int m;

int &max(int i, int j){//正確

m = i>j?i:j;

return m;

}

(3)int &max(int &i, int &j){//正確

return i>j?i:j;

}

引用和指針的對比

★相同點:

●都是地址的概念;

指針指向一塊內存,它的內容是所指內存的地址;而引用則是某塊內存的別名。

★不同點:

●指針是一個實體,而引用僅是個別名;

●引用只能在定義時被初始化一次,之後不可變;指針可變;引用“從一而終”,指針可以“見異思遷”;

●引用沒有const ,指針有const ,const 的指針不可變;(具體指沒有int& const a這種形式,而const int& a是有 的, 前者指引用本身即別名不可以改變,這是當然的,所以不需要這種形式,後者指引用所指的值不可以改變 )

●引用不能爲空,指針可以爲空;

●“sizeof 引用”得到的是所指向的變量( 對象) 的大小,而“sizeof 指針”得到的是指針本身的大小;

●指針和引用的自增(++) 運算意義不一樣;

●引用是類型安全的,而指針不是 ( 引用比指針多了類型檢查 )

發佈了115 篇原創文章 · 獲贊 48 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章