目錄
一、C++關(guān)鍵字
二、命名空間
2.1 C語言中的命名沖突?
2.2 C++中命名空間
2.2.1 命名空間的定義
2.2.2 命名空間的特性
2.2.3?命名空間的使用
2.2.4 補(bǔ)充知識(shí)
2.2.4 C++庫的命名空間
三、C++中的輸入&輸出
四、缺省參數(shù)
4.1? 定義
4.2 缺省參數(shù)的分類
4.2.1 全缺省參數(shù)
4.2.2?半缺省參數(shù)
4.3 示例:
五、函數(shù)重載
5.1 定義
5.2 函數(shù)重載示例
5.2.1?參數(shù)個(gè)數(shù)不同
5.2.1?參數(shù)類型不同
5.2.1 類型順序不同
5.3 為什么C++支持函數(shù)重載
六、引用
6.1 定義
6.2 引用特性
6.2.1 引用在定義時(shí)必須初始化
6.2.2 一個(gè)變量可以有多個(gè)引用
6.2.3 引用一旦引用了一個(gè)實(shí)體,再不能引用其他實(shí)體
6.3?引用做參數(shù)(輸出型參數(shù))
6.3.1 示例
6.3.2 效率比較
6.4 引用做返回值
6.4.1 引用做返回值的優(yōu)勢(shì)
6.4.2 性能比較??
6.4.3 引用缺點(diǎn)
6.5 常引用
6.6 引用和指針
七、auto關(guān)鍵字
7.1 概念
7.2 auto的使用事項(xiàng)
7.2.1 auto與指針和引用結(jié)合起來使用
7.2.2 在同一行定義多個(gè)變量
7.3 auto不能推導(dǎo)的場(chǎng)景
7.3.1 auto不能作為函數(shù)的參數(shù)
7.3.2 auto不能直接用來聲明數(shù)組
八、基于范圍的for循環(huán)
8.1 概念
8.2 使用條件
九、內(nèi)聯(lián)函數(shù)
9.1 概念
9.2 適用情況
9.3 注意問題
十、指針空值nullptr(C++)
? ?C++是在C語言的基礎(chǔ)上,容納進(jìn)去了面向?qū)ο蟮木幊趟枷?,并且增加了許多有用的庫,以及編程范式等,所以C++兼容C,也就是我們寫C語言的代碼在C++編譯環(huán)境下也依然能夠編譯通過。
注意:C++兼容C語言,本篇文章在前半部分主要還是用C語言的書寫習(xí)慣來講解C++中的命名空間,所以在前半部分使用的都還是#include<stdio.h>。
一、C++關(guān)鍵字
C++關(guān)鍵字一共有63個(gè)。
? ?在這里暫時(shí)不進(jìn)行逐一解釋,在后期博客會(huì)對(duì)此進(jìn)行分析,大家可以先去菜鳥教程中進(jìn)行了解,鏈接如下:C++ 的關(guān)鍵字(保留字)完整介紹 | 菜鳥教程 (runoob.com)。
二、命名空間
? ?在一方面來講C++是在C的基礎(chǔ)上的完善,所以C++要去解決C語言中出現(xiàn)的一些問題,首先就是命名沖突的問題。
2.1 C語言中的命名沖突?
? ?我們來觀察下面的兩個(gè)代碼:
代碼一:
#include<stdio.h>
int rand = 0;
int main()
{
printf("%d\n", rand);
return 0;
}
代碼二:
#include<stdio.h>
#include<stdlib.h>
int rand = 0;
int main()
{
printf("%d\n", rand);
return 0;
}
? ? ?對(duì)于上述的兩個(gè)代碼,代碼一可以正常運(yùn)行,但是代碼二無法正常運(yùn)行,這是為什么呢?
? ? 在上述圖片中,我們知道代碼二運(yùn)行不通過的原因是由于rand重定義,我們包含了庫中的頭文件,即?#include<stdlib.h>?,上述頭文件中定義了一個(gè)函數(shù)rand,包含頭文件相當(dāng)于把頭文件中的內(nèi)容在預(yù)編譯期間拷貝一份過來,相當(dāng)于在全局域中,在代碼二中我們也定義了一個(gè)全局變量rand,也在全局域中,這時(shí)就會(huì)有命名沖突的問題。
2.2 C++中命名空間
? ? 命名沖突有兩種:
- 和庫沖突。
- 和項(xiàng)目組中的其他人沖突。? ?
? ?我們知道不同的域中可以有同名的變量,C++解決了C語言中命名沖突的問題,C++使用namespace-命名空間(關(guān)鍵字)來解決命名沖突的問題,使用namespace定義一個(gè)域,用域進(jìn)行隔離。
2.2.1 命名空間的定義
? ?定義命名空間,需要使用到namespace關(guān)鍵字,后面跟命名空間的名字,然后接一對(duì){}即可,{} 中即為命名空間的成員。
? ?例如上述的代碼二,我們就可以定義一個(gè)名字是A的命名空間,rand就在A這個(gè)命名空間域了,將rand變量和stdlib.h中的rand函數(shù)進(jìn)行區(qū)分。
#include<stdio.h>
#include<stdlib.h>
namespace A
{
int rand = 0;
}
int main()
{
printf("%d\n", rand);
return 0;
}
? ?在上述代碼中,相當(dāng)于將全局變量rand定義到了一個(gè)名字是A的域中,而#include<stdlib.h>是將stdlib.h中的內(nèi)容拷貝到當(dāng)前文件中,其中的rand函數(shù)在全局域中,兩個(gè)rand命名的函數(shù)和變量不是處于同一個(gè)域,就解決了命名沖突的問題。
2.2.2 命名空間的特性
1.命名空間中可以定義變量/函數(shù)/類型。
namespace A
{
int rand = 0;
int Add(int x, int y)
{
return x + y;
}
struct A
{
int a[5];
char c;
};
}
2.命名空間可以嵌套。
? ?當(dāng)一個(gè)命名空間足夠大的時(shí)候,命名空間內(nèi)部的變量或者函數(shù)也會(huì)有命名沖突的問題,這時(shí)候就需要命名空間的嵌套了。
namespace A
{
int rand = 0;
int Add(int x, int y)
{
return x + y;
}
struct A
{
int a[5];
char c;
};
namespace B
{
int a = 0;
char c = 'k';
}
}
3.同一個(gè)工程中允許存在多個(gè)相同名稱的命名空間,編譯器最后會(huì)合成同一個(gè)命名空間中。
例如test.h和hll.cpp中都有A這個(gè)命名空間,在最后編譯運(yùn)行時(shí),會(huì)合成到同一個(gè)命名空間中去。
一個(gè)命名空間就定義了一個(gè)新的作用域,命名空間中的所有內(nèi)容都局限于該命名空間中。
2.2.3?命名空間的使用
#include<stdio.h>
namespace A
{
int a = 3;
}
int main()
{
printf("%d\n", a);
return 0;
}
? ?對(duì)于上述的代碼,編譯會(huì)不通過,在main函數(shù)中有要去打印變量a,但在搜索時(shí)并沒有找到變量a 的定義,這是由于在對(duì)變量a進(jìn)行搜索時(shí),我們不會(huì)主動(dòng)地去命名空間域中去搜索。
? ?對(duì)于命名空間域中的成員,我們不能直接使用,什么時(shí)候才去命名空間域搜索 ?
? ?命名空間中成員該怎么使用呢?
1.指定訪問命名空間域。
? ? ?在這里我們使用 ::(域作用限定符), ::加在變量的前面,表示去::左邊的域訪問。注意:如果左邊的域是空白,就代表是全局域。
#include<stdio.h>
namespace A
{
int a = 3;
}
int a = 5;
int main()
{
printf("%d\n", ::a); //::左邊是空白,代表去全局域訪問
printf("%d\n", A::a); //::左邊的域是A,代表去A這個(gè)命名空間域訪問
return 0;
}
2.將命名空間全部展開。(使用using namespace 命名空間名稱 引入)
#include<stdio.h>
namespace A
{
int a = 3;
}
using namespace A;
int main()
{
printf("%d\n", a);
return 0;
}
? ? ?使用using namespace A;將命名空間域A展開,但是展開就相當(dāng)于將A中的內(nèi)容放在全局中,我們使用命名空間的初衷是為了防止和別人或者和庫中的內(nèi)容有沖突,將自己定義的變量等使用作用域限定起來,使用using namespace A;將其展開,可能又會(huì)造成命名沖突的問題,所以我們不推薦使用這個(gè)方式,但是在我們平時(shí)寫代碼的過程中,命名沖突可能性小,所以使用這個(gè)方式。
3.把命名空間中常用的部分展開。
? ? C++的標(biāo)準(zhǔn)庫是使用的std這個(gè)命名空間,我們想要使用cout(輸出)和endl(換行),可以單獨(dú)將他們展開。
#include<iostream>
using std::cout;
using std::endl;
int main()
{
cout << "hello" << endl;
}
2.2.4 補(bǔ)充知識(shí)
? ?當(dāng)一個(gè)文件中有三個(gè)同名的變量,分別在局部域,全局域以及命名空間域,那么他們的訪問順序是怎樣的?
#include<stdio.h>
#include<stdlib.h>
int a = 0; //全局域
namespace A
{
int a = 3;
}
int main()
{
int a = 1; //局部域
printf("%d\n", a);
return 0;
}
? ? ?對(duì)于不同的域中的三個(gè)同名的變量來說,優(yōu)先去訪問局部變量,然后是全局變量,最后如果展開了命名空間域或者指定訪問才會(huì)去命名空間域。
2.2.4 C++庫的命名空間
? ?C++標(biāo)準(zhǔn)庫中的函數(shù)或者對(duì)象都是在命名空間std中定義的,所以我們要使用標(biāo)準(zhǔn)庫中的函數(shù)或者對(duì)象都要用std來限定。
? ?我們會(huì)發(fā)現(xiàn)在寫C++時(shí),我們?cè)诎^文件時(shí)不再加.h了,這是因?yàn)镃++有了命名空間這個(gè)定義之后,就把C++標(biāo)準(zhǔn)庫中的函數(shù)或者對(duì)象都用std這個(gè)命名空間包起來了,為了和舊的庫進(jìn)行區(qū)分,就定義了新的標(biāo)準(zhǔn),不再使用.h了。
三、C++中的輸入&輸出
? ?在這里由于沒有類和對(duì)象的知識(shí),所以簡(jiǎn)單的了解一下即可,之后會(huì)進(jìn)行講解。
? ?cout相當(dāng)于輸出函數(shù),cin相當(dāng)于輸入函數(shù),endl相當(dāng)于換行,注意cout和cin都可以連續(xù)一行插入或輸出多個(gè)變量,會(huì)自動(dòng)識(shí)別類型。
#include<iostream> //C++中標(biāo)準(zhǔn)庫,輸入輸出是由iostream庫提供的
using std::cout;
using std::endl;
using std::cin;
int main()
{
int a = 0;
int x = 0;
double d = 0;
cout << "hello" << " " << 'd' << ' ' << 's' << a << endl; //endl相當(dāng)于換行
cin >> x >> d;
cout << "hello" << " "<< x << " " << d << endl;
return 0;
}
四、缺省參數(shù)
? ? C++前期是在解決C語言中出現(xiàn)的問題,所以我們又引出了缺省參數(shù)這一概念。
4.1? 定義
? ?缺省參數(shù),聲明函數(shù)的時(shí)候可以讓 最右邊的連續(xù)若干個(gè) 參數(shù)有缺省值,在調(diào)用函數(shù)的時(shí)候,如果不寫相應(yīng)位置的參數(shù),則調(diào)用的參數(shù)就為缺省值。
例如:
#include<iostream> //C++中標(biāo)準(zhǔn)庫,輸入輸出是由iostream庫提供的
using std::cout;
using std::endl;
using std::cin;
void Func(int a = 0) //在形參位置上,給一個(gè)缺省值
{
cout << a << endl;
}
int main()
{
Func(); //沒有傳參時(shí),使用參數(shù)的默認(rèn)值
Func(5); //有傳參時(shí),使用指定的實(shí)參
return 0;
}
4.2 缺省參數(shù)的分類
4.2.1 全缺省參數(shù)
? ?全缺省參數(shù),即在聲明時(shí),給每一個(gè)形參一個(gè)缺省值。
#include<iostream> //C++中標(biāo)準(zhǔn)庫,輸入輸出是由iostream庫提供的
using std::cout;
using std::endl;
using std::cin;
void Func(int a = 0, int b = 5,int c = 8)
{
cout << "a =" << " " << a << endl;
cout << "b =" << " " << b << endl;
cout << "c =" << " " << c << endl;
}
int main()
{
Func();
Func(5);//將5傳給a
Func(5,10); //將5傳給a,將10傳給b
Func(5,10,6); //將5傳給a,將10傳給b, 將6傳給c
return 0;
}
? ?注意在這里傳參的時(shí)候,只能從左往右依次傳參,不能跳躍傳參。
//即不能如下:
Func(5, ,10);
4.2.2?半缺省參數(shù)
? ?半缺省,在聲明函數(shù)時(shí),給部分參數(shù)缺省值,但是這部分也有要求。
- 半缺省參數(shù)必須從右往左來給出,不能間隔著給。(如果從左往右來給出,那么在函數(shù)傳參時(shí)就無法分辨是給哪一個(gè)參數(shù)傳的值)
#include<iostream> //C++中標(biāo)準(zhǔn)庫,輸入輸出是由iostream庫提供的
using std::cout;
using std::endl;
using std::cin;
void Func(int a, int b = 5, int c = 8)
{
cout << "a =" << " " << a << endl;
cout << "b =" << " " << b << endl;
cout << "c =" << " " << c << endl;
}
int main()
{
Func(5);//將5傳給a
Func(5, 10); //將5傳給a,將10傳給b
Func(5, 10, 6); //將5傳給a,將10傳給b, 將6傳給c
return 0;
}
2.缺省參數(shù)不能在函數(shù)聲明和定義中同時(shí)出現(xiàn),是在聲明中出現(xiàn)。
例如我們?cè)趖est.h文件中提供Func函數(shù)的聲明,在Test.cpp文件中提供Func函數(shù)的定義:
? ? 在上述兩個(gè)文件中,我們?cè)诼暶?定義中都出現(xiàn)了缺省參數(shù),此時(shí)運(yùn)行不通過。
? ? ?為什么不允許聲明和定義中都給缺省值?為了避免如果在聲明和定義中給的缺省值不一致,那么編譯器按照哪一個(gè)來執(zhí)行的問題。
? ? ?那么是聲明給or定義給呢?
? ? ?當(dāng)然是聲明給。
如果定義給的話會(huì)出現(xiàn)以下的問題:
?
?
?
? ? ? 如果定義給,聲明不給,那么在編譯期間就會(huì)出錯(cuò)。
4.3 示例:
在這里我們使用之前寫過的棧的初始化來表示:
? ?對(duì)于上述棧的初始化,如果開辟空間小的話,要進(jìn)行擴(kuò)容,但是擴(kuò)容會(huì)有一定的消耗,但是如果開辟空間大的話,就會(huì)造成空間的浪費(fèi),我們可以使用缺省參數(shù),當(dāng)已經(jīng)知道需要開辟的空間大小時(shí)指定capacity的大小,未知時(shí),就使用缺省值。
五、函數(shù)重載
5.1 定義
? ?函數(shù)重載:是函數(shù)的一種特殊情況,C++允許在同一作用域中聲明幾個(gè)功能類似的同名函數(shù),這 些同名函數(shù)的形參列表(參數(shù)個(gè)數(shù) 或 類型 或 類型順序)不同,常用來處理實(shí)現(xiàn)功能類似數(shù)據(jù)類型 不同的問題。
? ?對(duì)于這樣的構(gòu)成函數(shù)重載的兩個(gè)函數(shù),在進(jìn)行函數(shù)調(diào)用時(shí),編譯器會(huì)自動(dòng)識(shí)別實(shí)參的類型來確定調(diào)用哪一個(gè)函數(shù)。
? ?注意:兩個(gè)同名函數(shù)只有返回類型不同,不構(gòu)成函數(shù)重載。
5.2 函數(shù)重載示例
5.2.1?參數(shù)個(gè)數(shù)不同
#include<iostream> //C++中標(biāo)準(zhǔn)庫,輸入輸出是由iostream庫提供的
#include"test.h"
using std::cout;
using std::endl;
using std::cin;
void f()
{
cout << "f()" << endl;
}
void f(int a)
{
cout << "f(int a)" <<a<< endl;
}
int main()
{
f();
f(5);
return 0;
}
? ?上述兩個(gè)函數(shù)的參數(shù)個(gè)數(shù)不同,構(gòu)成函數(shù)重載。
5.2.1?參數(shù)類型不同
#include<iostream> //C++中標(biāo)準(zhǔn)庫,輸入輸出是由iostream庫提供的
#include"test.h"
using std::cout;
using std::endl;
using std::cin;
int add(int x, int y)
{
cout << "int add(int x,int y)" << endl;
return x + y;
}
double add(double x, double y)
{
cout << "int add(double x,double y)" << endl;
return x + y;
}
int main()
{
cout << add(1, 2) << endl;
cout << add(1.2, 2.3) << endl;
return 0;
}
? ?上述的兩個(gè)函數(shù)函數(shù)名相同,他們的函數(shù)形參的類型不同,構(gòu)成函數(shù)重載。
5.2.1 類型順序不同
#include<iostream> //C++中標(biāo)準(zhǔn)庫,輸入輸出是由iostream庫提供的
#include"test.h"
using std::cout;
using std::endl;
using std::cin;
void f(int a,char b)
{
cout << "f(int a,char b)" << a << " " << b <<endl;
}
void f(char b,int a)
{
cout << "f(char b,int a)" << b << " " << a << endl;
}
int main()
{
f(5,'g');
f('g', 5);
return 0;
}
? ?上述兩個(gè)函數(shù)的形參參數(shù)類型順序不同,構(gòu)成函數(shù)重載。
5.3 為什么C++支持函數(shù)重載
? ?我們使用下面的例子來具體探討:
? ?要探索C++為什么支持函數(shù)重載,我們要從編譯鏈接過程來看。
? ? ? 在c語言中,生成的符號(hào)表中記錄的只有函數(shù)的名字以及地址,即類似于下方(下方只是粗大致畫的,實(shí)際中并不是這樣):
? ? ? 而在C++的符號(hào)表記錄中,會(huì)記錄形參的類型,所以它支持函數(shù)重載。
六、引用
? ?在c語言中,在學(xué)習(xí)指針的時(shí)候是一大難點(diǎn),C++中退推出了引用來更加方便的解決了一部分與指針相關(guān)的問題。
6.1 定義
? ?引用不是新定義一個(gè)變量,而是給已存在變量取了一個(gè)別名,編譯器不會(huì)為引用變量開辟內(nèi)存空 間,它和它引用的變量共用同一塊內(nèi)存空間。
類型& 引用變量名(對(duì)象名) = 引用實(shí)體;
注意:引用類型必須和引用實(shí)體是同一類型的。
? ?下面就是一個(gè)引用的例子:
int main()
{
int a = 0;
int& b = a; //b是a的別名,b和a使用的同一塊空間
int& c = b; //c是b的別名,b是a的別名,即c是a的別名,c,b和a使用的同一塊空間
cout << &a << endl;
cout << &b << endl;
cout << &c << endl;
return 0;
}
6.2 引用特性
6.2.1 引用在定義時(shí)必須初始化
int a = 0;
int& b = a; //b是a的別名,b和a使用的同一塊空間
int& c = b; //正確
int& d; //是錯(cuò)誤的,必須要初始化
6.2.2 一個(gè)變量可以有多個(gè)引用
#include<iostream>
using namespace std;
int main()
{
int a = 0;
int& b = a;
int& c = a;
}
6.2.3 引用一旦引用了一個(gè)實(shí)體,再不能引用其他實(shí)體
#include<iostream>
using namespace std;
int main()
{
int a = 0;
int& b = a;
int& c = a;
//引用一旦引用了一個(gè)實(shí)體,再不能引用其他實(shí)體
int x = 10;
c = x; //在這里是將x的值賦給c,c依舊是a/b的別名
return 0;
}
引用的使用場(chǎng)景
6.3?引用做參數(shù)(輸出型參數(shù))
6.3.1 示例
#include<iostream>
using namespace std;
void Swap(int& x, int& y)
{
int tmp = x;
x = y;
y = tmp;
}
int main()
{
int a = 10;
int b = 5;
Swap(a, b);
return 0;
}
? ?之前我們用函數(shù)實(shí)現(xiàn)交換兩個(gè)數(shù)的值,要用指針,在這里我們就可以使用引用了,x相當(dāng)于a的別名,y相當(dāng)于b的別名,改變x即改變a。
6.3.2 效率比較
? ?我們使用下面的函數(shù)來測(cè)試引用與非引用的效率。
#include<iostream>
using namespace std;
#include <time.h>
struct A { int a[10000]; };
void TestFunc1(A a){}
void TestFunc2(A& a){}
void TestRefAndValue()
{
A a;
// 以值作為函數(shù)參數(shù)
size_t begin1 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc1(a);
size_t end1 = clock();
// 以引用作為函數(shù)參數(shù)
size_t begin2 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc2(a);
size_t end2 = clock();
// 分別計(jì)算兩個(gè)函數(shù)運(yùn)行結(jié)束后的時(shí)間
cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}
int main()
{
TestRefAndValue();
return 0;
}
? ?我們可以看出使用引用 ,效率明顯提高。
6.4 引用做返回值
? ?下面我們會(huì)通過幾個(gè)代碼示例來具體體會(huì)引用做返回值的優(yōu)勢(shì)與弊端。
6.4.1 引用做返回值的優(yōu)勢(shì)
? ?在下面,我們會(huì)通過一段代碼的傳值返回和傳引用返回來比較用引用做返回值的優(yōu)勢(shì)。
? ?在下面的兩段代碼中我們使用傳值返回:
1. n是局部變量
int count()
{
int n = 0;
n++;
return n;
}
int main()
{
int ret = count();
return 0;
}
2.n是靜態(tài)變量
int count()
{
static int n = 0;
n++;
return n;
}
int main()
{
int ret = count();
return 0;
}
? ? ?我們會(huì)發(fā)現(xiàn)在上面的傳值返回中,不論函數(shù)中的變量是局部變量還是靜態(tài)變量,都需要有一個(gè)臨時(shí)變量協(xié)助完成返回,如果我們不想生成臨時(shí)變量怎么辦?用引用返回。
6.4.2 性能比較??
值和引用作為函數(shù)的返回值的性能比較:
#include<iostream>
using namespace std;
#include<time.h>
struct A { int a[1000]; };
A a;
//值返回
A TestFunc1() { return a; }
//引用返回
A& TestFunc2() { return a; }
void TestReturnByRefOrValue()
{
//以值返回作為函數(shù)的返回值類型
size_t begin1 = clock();
for (size_t i = 0; i < 100000; i++)
{
TestFunc1();
}
size_t end1 = clock();
//以引用作為函數(shù)的返回值類型
size_t begin2 = clock();
for (size_t i = 0; i < 100000; i++)
{
TestFunc2();
}
size_t end2 = clock();
//計(jì)算兩個(gè)函數(shù)運(yùn)算完成之后的時(shí)間
cout << "TestFunc1 time:" << end1 - begin1 << endl;
cout << "TestFunc2 time:" << end2 - begin2 << endl;
}
int main()
{
TestReturnByRefOrValue();
return 0;
}
6.4.3 引用缺點(diǎn)
? ?在一些時(shí)候,我們無法用引用作為返回值,它會(huì)導(dǎo)致一些錯(cuò)誤。
錯(cuò)誤示例:
?
int& count() //返回的是n的別名
{
int n = 0;
n++;
return n;
}
int main()
{
int ret = count();
return 0;
}
? ?在上述的情況下使用引用作為函數(shù)的返回類型,就會(huì)出問題,在上述代碼中出現(xiàn)了野指針的訪問。
? ?在上面的圖中,我們可以明顯的看到當(dāng)main函數(shù)調(diào)用count函數(shù)時(shí),n創(chuàng)建,當(dāng)調(diào)用結(jié)束,棧幀銷毀,n是在count函數(shù)中的局部變量,n的空間還給操作系統(tǒng)。
? ?在這里ret的值是不確定的,count函數(shù)返回的是n的別名,當(dāng)count函數(shù)調(diào)用結(jié)束,將n的別名對(duì)應(yīng)空間的值(即n的值)拷貝給ret,如果count函數(shù)調(diào)用結(jié)束,棧幀銷毀,沒有清理?xiàng)?,那么ret的結(jié)果僥幸是正確的,如果count函數(shù)調(diào)用結(jié)束,棧幀銷毀,清理?xiàng)敲磖et的結(jié)果是隨機(jī)值。
總結(jié):
1.基本任何場(chǎng)景都可以使用引用傳參。2.謹(jǐn)慎使用引用做返回值,出了函數(shù)作用域,變量就不在了,就不能使用引用返回,如果出了函數(shù)作用域,變量還在,就可以使用引用做返回類型。
6.5 常引用
? ?常引用是指利用 const 修飾的引用類型。 由于引用本身已經(jīng)綁定不可解綁,因此所用的 const 引用都是底層 const,即引用對(duì)象不能改變 (俗稱常引用)。
在引用的過程中,權(quán)限不能放大,但是引用過程中,權(quán)限可以平移或者縮小。
下面通過幾個(gè)例子來看常引用。
int a = 0;
int& b = a; //正確,b是a的別名
const int a = 0;
int& b = a; //錯(cuò)誤,a是const修飾的,不能改變,而b是int類型的引用,引用不能放大權(quán)限
const int c = 0;
int d = c; //正確,把c的值拷貝給d,沒有放大權(quán)限
int x = 0;
int& y = x; //正確,y是x的別名
const int& z = x; //正確,引用能夠縮小權(quán)限
int x = 0;
int& y = x;
const int& z = x; //當(dāng)z這個(gè)別名時(shí),x的值不能改變
++x; //當(dāng)是x這個(gè)名字時(shí),x的值可以改變
const int& m = 10; //m是常量10的別名,權(quán)限的平移
//當(dāng)類型不同時(shí),會(huì)發(fā)生隱式類型轉(zhuǎn)換,在轉(zhuǎn)換時(shí),中間會(huì)產(chǎn)生臨時(shí)變量,產(chǎn)生的臨時(shí)變量具有常性,
double dd = 1.11;
int ii = dd; //當(dāng)類型不同時(shí),會(huì)發(fā)生隱式類型轉(zhuǎn)換
int& isi = dd; //錯(cuò)誤
double dd = 1.11;
int ii = dd;
const int& rii = dd; //正確
int func1()
{
static int x = 0;
return x;
}
int main()
{
//int& ret = func1(); //錯(cuò)誤,函數(shù)返回時(shí)也會(huì)產(chǎn)生一個(gè)臨時(shí)變量,臨時(shí)變量具有常性,此處是對(duì)權(quán)限的擴(kuò)大
const int& ret = func1(); //正確,權(quán)限的平移
return 0;
}
6.6 引用和指針
七、auto關(guān)鍵字
? ?隨著程序越來越復(fù)雜,程序中用到的類型也越來越復(fù)雜,可能出現(xiàn)類型難于拼寫等問題,這時(shí)C++就提出了auto關(guān)鍵字。
7.1 概念
int main()
{
int a = 0;
int b = a;
auto c = b; //根據(jù)右邊的表達(dá)式自動(dòng)推導(dǎo)c的類型
auto d = 1 + 1.11; //根據(jù)右邊的表達(dá)式自動(dòng)推導(dǎo)d的類型
//typeid可以打印類型
cout << typeid(c).name() << endl;
cout << typeid(d).name() << endl;
return 0;
}
? ?注意:
? ?使用auto定義變量時(shí)必須對(duì)其進(jìn)行初始化,在編譯階段編譯器需要根據(jù)初始化表達(dá)式來推導(dǎo)auto 的實(shí)際類型。因此auto并非是一種“類型”的聲明,而是一個(gè)類型聲明時(shí)的“占位符”,編譯器在編 譯期會(huì)將auto替換為變量實(shí)際的類型。
7.2 auto的使用事項(xiàng)
7.2.1 auto與指針和引用結(jié)合起來使用
? ?用auto聲明指針類型時(shí),用auto和auto*沒有任何區(qū)別,但用auto聲明引用類型時(shí)則必須加&。
int main()
{
int x = 10;
auto a = &x; //推導(dǎo)出來a是指針
auto* b = a; //指定必須是指針
auto& c = x; //指定是引用
return 0;
}
7.2.2 在同一行定義多個(gè)變量
? ?當(dāng)在同一行聲明多個(gè)變量時(shí),這些變量必須是相同的類型,否則編譯器就會(huì)報(bào)錯(cuò),因?yàn)榫幾g器實(shí)際上只對(duì)第一個(gè)類型進(jìn)行推導(dǎo),然后用推導(dǎo)出來的類型定義其他變量。
auto a = 10, b = 2;
//auto ac = 0, d=1.11;//錯(cuò)誤
7.3 auto不能推導(dǎo)的場(chǎng)景
7.3.1 auto不能作為函數(shù)的參數(shù)
// 此處代碼編譯失敗,auto不能作為形參類型,因?yàn)榫幾g器無法對(duì)a的實(shí)際類型進(jìn)行推導(dǎo)
void TestAuto(auto a)
{}
7.3.2 auto不能直接用來聲明數(shù)組
void TestAuto()
{
int a[] = { 0,1,2 };
//auto a[] = { 4,3,5 }; //錯(cuò)誤
}
八、基于范圍的for循環(huán)
8.1 概念
int main()
{
int arr[] = { 1,2,3,4,5 };
//c語言中訪問數(shù)組
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
arr[i] *= 2;
for(int *p=arr; p<arr+ sizeof(arr) / sizeof(arr[0]);p++)
cout<<*p<<endl;
//范圍for
//依次取數(shù)組中數(shù)據(jù)賦值給e
//自動(dòng)迭代,自動(dòng)判斷結(jié)束
for (auto e : arr)
{
cout << e << " ";
}
cout << endl;
return 0;
}
如果我們要使用范圍for來修改數(shù)組中的數(shù)據(jù):
int main()
{
//修改數(shù)據(jù)
//錯(cuò)誤,取arr中數(shù)據(jù)依次賦值給e,相當(dāng)于依次取arr[0]、arr[1]......拷貝給e,e的改變不會(huì)影響數(shù)組的內(nèi)容
for (auto e : arr)
{
e *= 2;
}
//正確,e開始是arr[0]別名,然后是arr[1]別名,e的修改會(huì)影響數(shù)組
for (auto& e : arr)
{
e *= 2;
}
return 0;
}
? ?注意上述的范圍for中,auto,e都可以改變,arr是數(shù)組。
8.2 使用條件
for循環(huán)迭代的范圍必須是確定的。
int main()
{
int arr[] = { 0,1,2,3,4,5 };
int* p = arr;
//錯(cuò)誤,因?yàn)閒or的范圍不確定
for (auto& e : p)
{
e *= 2;
}
return 0;
}
九、內(nèi)聯(lián)函數(shù)
9.1 概念
9.2 適用情況
? ?內(nèi)聯(lián)函數(shù)適用于短小的頻繁調(diào)用的函數(shù),inline對(duì)于編譯器僅僅只是一個(gè)建議,最終是否成為inline,編譯器自己決定。
? ?內(nèi)聯(lián)函數(shù)不適用于:1. 比較長(zhǎng)的函數(shù)? ? ?2. 遞歸函數(shù)
inline int Add(int x, int y)
{
return (x + y) * 10;
}
int main()
{
for (int i = 0; i < 100; i++)
{
cout << Add(i, i + 1) << endl;
}
return 0;
}
9.3 注意問題
? ?inline不建議聲明和定義分離,分離會(huì)導(dǎo)致鏈接錯(cuò)誤。因?yàn)閕nline被展開,就沒有函數(shù)地址了,鏈接就會(huì)找不到。文章來源:http://www.zghlxwxcb.cn/news/detail-731284.html
十、指針空值nullptr(C++)
void Testptr()
{
int* p1 = NULL;
}
void f(int)
{
cout << "f(int)" << endl;
}
void f(int*)
{
cout << "f(int*)" << endl;
}
int main()
{
f(0);
f(NULL);
f((int*)NULL);
return 0;
}
? ?在上述代碼中,我們想要調(diào)用void f(int*),但是發(fā)現(xiàn)每次調(diào)用的都是void f(int),在C++98中,字面常量0既可以是一個(gè)整形數(shù)字,也可以是無類型的指針(void*)常量,但是編譯器默認(rèn)情況下將其看成是一個(gè)整形常量,如果要將其按照指針方式來使用,必須對(duì)其進(jìn)行強(qiáng)轉(zhuǎn)(void*)0。文章來源地址http://www.zghlxwxcb.cn/news/detail-731284.html
到了這里,關(guān)于C++入門(保姆級(jí)教程)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!