C++:名稱空間、預設引數、函式過載、引用、行內函數
一.名稱空間
在C/C++中,變數、函式和類都是大量存在的,這些變數、函式和類的名稱都將作用於全域性作用域中,可能會導致很多衝突,所以我們就選擇使用名稱空間。
名稱空間的目的是對識別符號的名稱進行本地化,以避免命名衝突或者名字汙染。
1.定義:
定義一個名稱空間,需要用到namespace關鍵字,後跟名稱空間。
namespace n1//普通的名稱空間 { int a = 10;//定義變數 int b = 20; int add(int left, int right)//定義函式 { return left + right; } } namespace n2 { int c = 30; int sub(int left, int right) { return left - right; } namespace n3//名稱空間可以巢狀 { int mul(int left, int right) { return left*right; } } } namespace n1//同一個工程中允許多個相同名稱的名稱空間,編譯器會將多個合成一個名稱空間 { int c = 50; }
2.使用(三種方式)
(1)使用作用域限定符
int main()
{
printf("%d\n",n1::a );
system("pause");
return 0;
}
(2)使用using將名稱空間中的成員引入
using n1::b; int main() { printf("%d\n", b); system("pause"); return 0; }
(3)使用using namespace名稱空間名稱引入
using namespace n1;
int main()
{
printf("%d\n", add(10, 20));
system("pause");
return 0;
}
二.預設引數
1.概念
預設引數是宣告或者定義函式時對函式的引數指定一個預設值。在呼叫函式時,如果沒有指定實參則採用預設值,否則使用指定的實參。
void test(int a = 100)
{
cout << a << endl;
}
int main()
{
test();//無參
test(10);//有參
system("pause");
return 0;
}
2.分類
(1)全預設引數
(2)半預設引數
void test(int a = 100, int b = 10, int c = 1)//全預設引數
{
cout << "a=" << a << endl;
cout << "b=" << b << endl;
cout << "c=" << c << endl;
}
void test(int a, int b = 10, int c = 1)//半預設引數
{
cout << "a=" << a << endl;
cout << "b=" << b << endl;
cout << "c=" << c << endl;
}
3.特點
(1)半預設引數必須從右到左依次給出,不能間隔。
(2)預設引數不能同時在函式宣告和定義中出現。
(3)預設值必須是常量或者全域性變數
(4)C語言不支援
三.函式過載
1.函式過載是函式的一種特殊情況,C++允許在同一個作用域中宣告幾個功能類似的同名函式,這些同名函式的形參必須不同。常用於處理功能類似但是型別不同的問題。
int add(int a, int b)
{
return a + b;
}
double add(double a, double b)
{
return a + b;
}
long add(long a, long b)
{
return a + b;
}
short add(short a, short b)
{
return a + b;
}
int main()
{
int ret1 = add(1, 2);
double ret2 = add(1.0, 2.0);
long ret3 = add(1L, 2L);
short ret4 = add(1, 2);
system("pause");
return 0;
}
extern"C"在C++工程中將某個函式按照C的風格來編譯。
四.引用
1.概念
引用不是定義一個變數,而是給已存在的變數去一個別名, 編譯器不會為引用變數開闢記憶體空間,它和它的引用空間公用一塊記憶體空間。
void test()//引用型別必須和引用實體是同類型的
{
int a = 10;
int & ra = a;
printf("%p\n", &a);
}
2. 特性
(1)引用在定義時必須初始化
(2)一個變數可以有多個引用
(3) 引用一旦引用了一個實體,再不能引用其他實體
void test1()//引用型別必須和引用實體是同類型的
{
int a = 10;
//int &ra;//這條語句會出錯
int & ra = a;
int& rra = a;
printf("%p\n", &a);
printf("%p\n", &ra);
printf("%p\n", &rra);
}
3. 常引用
void test()
{
const int a = 10;
//int & ra = a; //出錯
const int& rra = a;
double b = 20.0;
//int& rb = b; //出錯
const double&rrb = b;
}
4.使用場景
(1)作引數
void swap(int& x, int& y)
{
int tmp = x;
x = y;
y = tmp;
}
(2)作返回值
int& testret(int&a)
{
a = a + 10;
return a;
}
5.傳值、傳地址、傳引用效率比較
struct A
{
int arr[10000];
int size;
};
void testref(A& param)
{
}
void test()
{
A a;
size_t begin = GetTickCount();//從開機到現在的時間
for (size_t i = 0; i < 1000000; i++)
testref(a);//傳指標 16 傳引用 15
size_t end = GetTickCount();
cout << end - begin << endl;
}
通過比較,我們發現引用和指標在傳參的效果幾乎相同
6.引用和指標的區別
(1)引用自在定義時必須初始化,指標沒有要求;
(2)引用在初始化時引用一個實體後,就不能在引用其他實體,而指標可以在任何時候指向一個同類型實體;
(3)沒有NULL引用,有NULL指標;
(4)在sizeof中含義不同,引用的結果為引用型別的大小;指標永遠就是地址所佔的位元組數;
(5)引用自加一即是引用實體增加一,指標自加一即是指標向後偏移一個型別的大小;
(6)有多級指標,但是沒有多級引用;
(7)訪問實體型別不同;指標需要顯示解引用,引用編譯器自己處理
(8)引用比指標使用起來相對更安全
五.行內函數
1.概念
以inline修飾的函式叫作行內函數,編譯時C++編譯器會在呼叫行內函數的地方展開,沒有函式壓棧的開銷,行內函數提升程式執行效率。
int add(int x, int y)
{
return x + y;
}
int main()
{
int ret = 0;
ret = add(10, 20);
cout << ret << endl;
system("pause");
return 0;
}
在release下,彙編程式碼中沒有call;
在debug下,先對編譯器修改;如下:專案-->xxx.cpp屬性-->配置(Debug)
沒有call指令
2.特性
(1)inline是一種以空間換取時間的做法,省去呼叫函式的開銷,所以程式碼很長或者有迴圈/遞迴的函式不適合使用行內函數。
(2)inline對於編譯器而言只是一個建議,編譯器會自動優化,如果定義為inline的函式中有迴圈/遞迴等等,編譯器會在優化時忽略掉行內函數。