1. 程式人生 > >C++名稱空間&預設引數&函式過載

C++名稱空間&預設引數&函式過載

名稱空間

使用名稱空間是要對識別符號的名稱進行本地初始化,避免命名衝突。

定義名稱空間需要用到namespace關鍵字,後跟名稱空間的名字,在{}內為名稱空間的成員

//普通的名稱空間
namespace N1{ //名稱空間的名稱為N1
	//可定義變數也可以定義函式
	int a = 10;
	int add(int x, int y){
		return x + y;
	}
}

//巢狀的名稱空間
namespace N2{
	int a = 20;
	int b = 30;
	int add(int x, int y){
		return x + y;
	}
	
	namespace N3{
		int a = 10;
		int sub(int x, int y){
			return x - y;
		}
	}
}

//同一工程中允許存在多個相同名稱的明明空間
//編譯器會合成同一個名稱空間
namespace N1{
	//int a = 30;  //錯誤,之前已經定義變數a
	int mul(int x, int y){
		return x * y;
	}
}

名稱空間通過作用域限定符::來使用

#include <iostream>
using namespace std;

namespace N{
	int a = 10;
	int b = 20;
	int add(int x, int y){
		return x + y;
	}
}

int a = 50;

int main()
{
	int a = 90;
	cout<<a<<endl;
	cout<<::a<<endl;
	cout<<N::a<<endl;
	return 0;
}

上面通過作用域限定符來使用名稱空間,還可以通過關鍵字using將名稱空間成員引用

using N::a;
int main()
{
	cout<<a<<endl;
}

使用using namespace引入名稱空間:

using namespace N;
int main()
{
	cout<<a<<endl;
	add(10, 30);
	return 0;
}

預設引數

預設引數就是在宣告或者定義函式時為函式的引數指定一個或多個預設值,在使用該函式時,如果沒有指定的引數,就使用預設值

void test(int a = 10)
{
	cout<<a<<endl;
}

int main()
{
	test(); //沒有傳參使用預設值10
	test(20); //傳參使用指定引數20
}

預設引數分為全預設引數和半預設引數

//全預設引數
void test(int a = 10, int b = 20, int c = 30)
{
	cout<<a<<endl;
	cout<<b<<endl;
	cout<<c<<endl;
}
//半預設引數
void test(int a, int b = 20, int c = 30)
{
	cout<<a<<endl;
	cout<<b<<endl;
	cout<<c<<endl;
}

半預設引數的引數必須從左到右依次來給,不能出現間隔,並且預設引數不能在定義和宣告中同時出現(一般出現在宣告中),預設引數必須是全域性變數或者常量

函式過載

函式過載是函式的一種特殊情況,C++允許在同一作用域中宣告幾個功能類似的同名函式,這些同名函式的形參列表(引數個數,型別,順序)必須不同,函式過載通常是編譯器在編譯階段根據實參確定的,常用來處理實現功能類似資料型別不同的問題。

int add(int x, int y)
{
	return x + y;
}

double add(double x, double y)
{
	return x + y;
}

long add(long x, long y)
{
	return x + y;
}

int main()
{
	add(1, 2);
	add(2.0, 4.3);
	return 0;
}

兩個函式只有返回值不同,是不能形成過載的,根據過載的定義可以知道,只有形參列表不同時,才可以形成函式過載,另外,無參函式和全預設函式儘量不要過載,會形成歧義,編譯器無法確定該執行哪個函式。

那麼C++底層是如何實現過載的呢,我們可以先來看一段簡單的過載程式碼

#include <iostream>
using namespace std; 

int add(int x, int y);
double add(double x, double y);

int main()
{
	add(1, 2);
	add(1.0, 2.0);
	return 0;
}

在Linux環境下通過命令來讓程式停止在彙編階段

g++ -S test.cpp -o test.s

可以看到編譯器在底層呼叫的不是add函式,而是_Z3addii和_Z3adddd兩個函式,所以我們猜想編譯器會在底層對過載函式重新進行修飾,被重新修飾後的名字中包含了:函式的名字以及引數型別。這就是為什麼函式過載中幾個同名函式要求其引數列表不同的原因。只要引數列表不同,編譯器在編譯時通過對函式名字進行重新修飾,將引數型別包含在最終的名字中,就可保證名字在底層的全域性唯一性。C語言不支援函式過載的原因就是編譯器不會去修飾函式名,在底層也還是用add這個單純的函式名。

當然我們有時候需要在C++中用C的語法來編譯某些函式,在這些函式之前加上extern "C"即可。