1.命名空間的介紹
首先我們看到如下的代碼,在C語言中:
#include <stdio.h>
#include <stdlib.h>
int rand = 10;
// C語言沒辦法解決類似這樣的命名沖突問題,所以C++提出了namespace來解決
int main()
{printf("%d\n", rand);return 0;
}
// 編譯后后報錯:error C2365: “rand”: 重定義;以前的定義是“函數”
// 在掃雷小游戲中,使用到了rand函數生成隨機數
在C/C++中,變量、函數和后面要學到的類都是大量存在的,這些變量、函數和類的名稱將都存 在于全局作用域中,可能會導致很多沖突。使用命名空間的目的是對標識符的名稱進行本地化, 以避免命名沖突或名字污染,namespace關鍵字的出現就是針對這種問題的。
使用namespace關鍵字定義屬于我們自己的命名空間:namespace關鍵字后面加上命名空間的名字,然后接一對{}即可,{} 中即為命名空間的成員。如下:
// jess是命名空間的名字。
// 1. 正常的命名空間定義
namespace jess
{// 命名空間中可以定義變量/函數/類型int rand = 10;int Add(int x, int y){return x + y;}struct Node{struct Node* next;int val;};
}//2. 命名空間可以嵌套--這里命名空間N1中嵌套了N2
// test.cpp
namespace N1
{int a;int b;int Add(int x, int y){return x + y;}namespace N2{int c;int d;int Sub(int x, int y){return x - y;}}
}//3. 同一個工程中允許存在多個相同名稱的命名空間,編譯器最后會合成同一個命名空間中。
// ps:一個工程中的test.h和上面test.cpp中兩個N1會被合并成一個
// test.h
namespace N1
{int Mul(int x, int y){return x * y;}
}
注意:一個命名空間就定義了一個新的作用域,命名空間中的所有內容都局限于該命名空間中
定義了屬于自己的命名空間后,應該如何使用呢?
有三種使用方式:
1.加命名空間名稱及作用域限定符(空間名稱::需要訪問的變量/函數)
namespace jess
{// 命名空間中可以定義變量/函數/類型int a = 10;int Add(int x, int y){return x + y;}int main()
{printf("%d\n", jess::a);return 0; ? ?
}
2.使用using將命名空間中某個成員引入
namespace jess
{// 命名空間中可以定義變量/函數/類型int a = 10;int b = 20;int Add(int x, int y){return x + y;}using jess::b; // 使用using將命名空間中某個成員引入
int main()
{printf("%d\n", jess::a);printf("%d\n", b);return 0; ? ?
}
3.使用using namespace 命名空間名稱引入
namespace jess
{// 命名空間中可以定義變量/函數/類型int a = 10;int b = 20;int Add(int x, int y){return x + y;}using namespce jess; // 使用using namespace 命名空間名稱引入int main()
{printf("%d\n", N::a);printf("%d\n", b);int ret = Add(10, 20);return 0; ? ?
}
2.C++中如何實現輸入和輸出
?還記得,C語言第一課講的是如何在屏幕中打印hello world!C語言如下:
#include <stdio.h>int main()
{printf("hello world!");return 0;
}
C++如下:
#include <iostream>
// std是C++標準庫的命名空間名,C++將標準庫的定義實現都放到這個命名空間中
using namespace std;
int main()
{cout<<"Hello world!"<<endl;return 0;
}
補充說明:
1. 使用cout標準輸出對象(控制臺)和cin標準輸入對象(鍵盤)時,必須包含< iostream >頭文件以及按命名空間使用方法使用std。
2. cout和cin是全局的流對象,endl是特殊的C++符號,表示換行輸出,他們都包含在包含< iostream >頭文件中。
3. <<是流插入運算符,>>是流提取運算符(后續會提到)。
4. 使用C++輸入輸出更方便,不需要像printf/scanf輸入輸出時那樣,需要手動控制格式。 C++的輸入輸出可以自動識別變量類型。
5. 實際上cout和cin分別是ostream和istream類型的對象(后續會提到)。
#include <iostream>
using namespace std;int main()
{int a;double b;char c;// 可以自動識別變量的類型cin>>a; // 從鍵盤中讀取數值,存放到變量a的地址中cin>>b>>c; // 從鍵盤中依次讀取數值(空格分隔),存放到變量b、c的地址中cout<<a<<endl; // 在終端中打印a的值并且換行cout<<b<<" "<<c<<endl; // 在終端中打印b的值再打印一個空格再打印c最后換行return 0;
}
3.缺省參數?
缺省參數是聲明或定義函數時為函數的參數指定一個缺省值。在調用該函數時,如果沒有指定實 參則采用該形參的缺省值,否則使用指定的實參。如下:
#include <iostream>
using namespace std;void Test(int a = 0)
{cout<<"a = "<<a<<endl;
}
int main()
{Test(); ? ? // 沒有傳參時,使用參數的默認值,打印:a = 0Test(10); ? // 傳參時,使用指定的實參,打印:a = 10return 0;
}
3.1全缺省參數
#include <iostream>
using namespace std;void Test(int a = 10, int b = 20, int c = 30){cout<<"a = "<<a<<endl;cout<<"b = "<<b<<endl;cout<<"c = "<<c<<endl;}int main()
{Test(); ? ? // 沒有傳參時,使用參數的默認值,打印:a = 10 b=20 c=30Test(1); ? // 傳參時,使用指定的實參,打印::a = 1 b=20 c=30return 0;
}
3.2半缺省參數
#include <iostream>
using namespace std;void Test(int a, int b = 20, int c = 30){cout<<"a = "<<a<<endl;cout<<"b = "<<b<<endl;cout<<"c = "<<c<<endl;}int main()
{// 此時第一個位置的參數必須傳遞Test(1); ? ? // 沒有傳參時,使用參數的默認值,打印:a = 1 b=20 c=30Test(1,2); ? // 傳參時,使用指定的實參,打印::a = 1 b=2 c=30return 0;
}
注意:
1. 半缺省參數必須從右往左依次來給出,不能間隔著給
2. 缺省參數不能在函數聲明和定義中同時出現
// 正確做法:
// 缺省參數只在聲明中指定(通常在頭文件),定義中不能重復指定。如下:// 聲明(.h文件):指定缺省參數
void func(int a = 10); // 定義(.cpp文件):不能重復缺省參數
void func(int a) { // 正確,無缺省值// ...
}
3. 缺省值必須是常量或者全局變量
// 錯誤例子
void func(int a = x) // 錯誤!x是局部變量,編譯時無法確定其值
{cout<<a<<endl;
}int main()
{int x = 5;func(); // 無法確定用什么值替換return 0;
}// 正確例子
int g = 20; // 全局變量void func(int a = 10, int b = g) // 10是常量,g是全局變量,都符合語法
{ // ...
}
4. C語言不支持(編譯器不支持)
4.函數重載
函數重載:是函數的一種特殊情況,C++允許在同一作用域中聲明幾個功能類似的同名函數,這 些同名函數的形參列表(參數個數 或 類型 或 類型順序)不同,常用來處理實現功能類似數據類型不同的問題。
#include<iostream>
using namespace std;// 1、參數類型不同
int Add(int x, int y)
{cout << "int Add(int x, int y)" << endl;return x+ y;
}double Add(double x, double y)
{cout << "double Add(double x, double y)" << endl;return x+ y;
}// 2、參數個數不同
void f()
{cout << "f()" << endl;
}void f(int a)
{cout << "f()" << endl;
}// 3、參數類型順序不同
void f(int a, char b)
{cout << "f(int a,char b)" << endl;
}void f(char b, int a)
{cout << "f(char b, int a)" << endl;
}int main()
{Add(10, 20);Add(10.1, 20.2);f();f(10);f(10, 'a');f('a', 10);return 0;
}
為什么C++支持函數重載,而C語言不支持函數重載呢?(這里簡單講一下)
在C/C++中,一個程序要運行起來,需要經歷以下幾個階段:預處理、編譯、匯編、鏈接。其中在編譯過程中C/C++對函數的命名規則是不一樣的。C語言對函數的命名規則是:函數名本身;C++對函數的命名規則是:Z_+函數名字符個數+參數類型的首字母。例如Add函數在C/C++在中編譯后的結果(此處說的命名規則是在在linux下,采用gcc編譯得到):
C語言為什么不支持重載,因為無法區分同名函數。而C++是通過函數修飾規則來區分,只要參數不同,修飾出來的名字就不一樣,就支持了重載。
注意:如果兩個函數函數名和參數是一樣的,返回值不同是不構成重載的,因為調用時編譯器沒辦 法區分。