真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

面向?qū)ο笈cC++基礎(chǔ)—基礎(chǔ)篇(上)-創(chuàng)新互聯(lián)

文章目錄
  • 6. 基礎(chǔ)篇(上篇)
    • (1). 真正的bool類型
    • (2). auto—自動(dòng)推斷變量類型(C++11)
    • (3). decltype()—根據(jù)某個(gè)值推斷類型
    • (4). namespace—命名空間
    • (5). ::—域解析操作符
    • (6). using—typedef的C++版本
      • #1.using + 對(duì)象/函數(shù)/變量;
      • #2.using namespace + 命名空間;
      • #3.using A = B;
    • (7). {}—初始化列表(C++11)
    • (8). &與&&—引用類型
      • #1.沒(méi)見(jiàn)過(guò)的奇怪表示
      • #2.引用(Reference)的概念
      • #3.引用的本質(zhì)—指針常量
      • #4.左值(lvalue)、將亡值(xvalue)與純右值(prvalue)
      • #5.常量引用(Const Reference)
      • #6.右值引用
      • #7.傳引用的函數(shù)
      • #8.返回引用的函數(shù)以及一些危險(xiǎn)的操作
    • 小結(jié)

成都創(chuàng)新互聯(lián)堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:網(wǎng)站設(shè)計(jì)制作、成都網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的瀍河網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!6. 基礎(chǔ)篇(上篇)

? 在這一篇中,我們會(huì)講一講C++的基本語(yǔ)法,事實(shí)上這一章講的更多的應(yīng)該是從C語(yǔ)言到C++的語(yǔ)法演變,看完這一篇之后,你應(yīng)該可以寫出更加符合C++習(xí)慣的代碼。

? C++由貝爾實(shí)驗(yàn)室的Bjarne Stroustrup發(fā)明,沒(méi)錯(cuò),又是貝爾實(shí)驗(yàn)室,C語(yǔ)言也是在貝爾實(shí)驗(yàn)室誕生的。C++最初名為C with classes,是比較簡(jiǎn)單地在C語(yǔ)言的基礎(chǔ)上增加了面向?qū)ο蟮某绦蛟O(shè)計(jì)模式。
? 在1998年,C++98標(biāo)準(zhǔn)推出,這也是第一個(gè)由國(guó)際標(biāo)準(zhǔn)化組織負(fù)責(zé)的C++標(biāo)準(zhǔn),后續(xù)推出的C++03,C++11,C++14等標(biāo)準(zhǔn)為C++引入了各種各樣的全新特性,關(guān)于C++標(biāo)準(zhǔn)中的一些特性,你可以參考:cppreference.com,網(wǎng)站中有著對(duì)各個(gè)標(biāo)準(zhǔn)的特性的簡(jiǎn)明解釋以及各編譯器對(duì)相應(yīng)特性的支持情況。

(1). 真正的bool類型

? 在C語(yǔ)言當(dāng)中,我們用0表示假,非0的任何數(shù)字表示真,有的時(shí)候可能會(huì)有點(diǎn)別扭,實(shí)際上我們可以在C中引入stdbool.h這個(gè)頭文件來(lái)增加true和false兩個(gè)宏定義,不過(guò)終究只是宏定義,不算是真正的bool類型。
? C++中引入了真正的bool類型,我們可以使用以下的方式聲明并定義一個(gè)變量:

bool a = true;
bool b{false};

? 用小寫的true和false表示真和假,關(guān)于第二行的初始化方式我們之后會(huì)提到。

(2). auto—自動(dòng)推斷變量類型(C++11)

? C++11標(biāo)準(zhǔn)中將auto關(guān)鍵字的語(yǔ)義做了修改,事實(shí)上是很大的改動(dòng),在C以及C++11之前的標(biāo)準(zhǔn)中,auto代表由編譯器決定變量存放在內(nèi)存的位置,與之對(duì)應(yīng)的是register關(guān)鍵字,代表希望將變量存放在寄存器當(dāng)中,當(dāng)然,編譯器不一定會(huì)聽(tīng)哈。
? 不過(guò)好像,我們?cè)贑語(yǔ)言中聲明變量的時(shí)候沒(méi)有寫過(guò)這個(gè)auto???沒(méi)錯(cuò),如果一個(gè)變量聲明的時(shí)候不寫auto,它就默認(rèn)是auto的,只有聲明了是register的情況下才會(huì)是register,所以好像,把a(bǔ)uto關(guān)鍵字去掉也不是什么大事對(duì)吧?
? register在上一部教程里貌似沒(méi)提到,如今的計(jì)算機(jī)運(yùn)算速度很快,一般寫程序是不太會(huì)用到的,不過(guò)如果你有一個(gè)OIer同學(xué),他肯定知道這個(gè)東西有什么用(常數(shù)優(yōu)化),我們就不細(xì)講了。

? 接下來(lái)就正式引入一下C++11標(biāo)準(zhǔn)中的auto,編譯器還是具備相當(dāng)?shù)闹悄艿?,雖然這么說(shuō)也不至于,因?yàn)樵缇陀辛艘惶酌鞔_的推斷字面量類型的規(guī)則了,例如一個(gè)不超過(guò)int的數(shù)字字面量就為int,bool就是bool,一般的浮點(diǎn)數(shù)字面量為double;后面帶標(biāo)識(shí)符的比如1.23f就是float,123ll就是long long,就是這么簡(jiǎn)單,所以只要判斷一下就行,還是相當(dāng)簡(jiǎn)單的:

#includeint main()
{auto a = 1.23f;
    auto b = 234;
    std::cout<< "Type of a is "<< typeid(a).name()<< std::endl<< "Type of b is "<< typeid(b).name()<< std::endl;
    return 0;
}

p3

? typeid(var).name()可以返回變量的類型名,我這里是使用了VS,如果是gcc編譯器,結(jié)果可能是f和i,不過(guò)不影響就是了。
? 使用auto關(guān)鍵字有兩個(gè)比較重要的點(diǎn),首先是auto關(guān)鍵字只能在變量定義的時(shí)候使用,因?yàn)閍uto關(guān)鍵字說(shuō)到底也只是根據(jù)被賦予的初始值在編譯器確定類型,因此在C++中不存在 “自由變量”,可以像python一樣任意變換類型。
? 二來(lái)是如果多個(gè)變量在同一行定義,他們必須保證是同一個(gè)類型的,即便前面是auto,例如:

auto a = 1.23f, b = 234;

? 在VS中會(huì)直接提示代碼錯(cuò)誤,而在Dev-C++中,會(huì)在編譯的時(shí)候報(bào)錯(cuò),我們必須保證同一行的所有變量的類型都是一致的,否則就只能分行寫了。

? 所以雖然auto看起來(lái)很令人心潮澎湃,它還是把C++限制在了同一變量名不可改變的規(guī)則之下,如果真的要變,你可能得參考一下C++的模板(template),之后也會(huì)講到。

? 聽(tīng)到這里其實(shí)還是挺心潮澎湃的,至少C++向著自動(dòng)化的方向邁進(jìn)了一大步,那auto能不能作為函數(shù)返回的類型呢?在C++11里不能,C++14里就可以了,比如下面這一段代碼:

auto func(auto a, auto b)
{return a + b;
}

? 這段代碼在C++14中可以編譯通過(guò),C++11中不行,C++11中得這么寫:

templateauto func(T1 a, T2 b) ->decltype(a+b)
{return a + b;
}

? 看完之后內(nèi)心:…,還是別這么寫了吧,要么用C++14,要么就好好寫變量類型,不過(guò)我還是要解釋一下,template是模板關(guān)鍵字,C++11中因?yàn)閍uto在a和b之前出現(xiàn),沒(méi)有辦法推斷類型,因此要在后面加一個(gè)->表示返回類型,decltype()下一節(jié)會(huì)說(shuō),是表示函數(shù)內(nèi)表達(dá)式的值的類型。真的,相當(dāng)麻煩,別這么寫了就。

? 還有一個(gè)要注意的點(diǎn)是,auto不能作為數(shù)組的類型出現(xiàn),即便后面有對(duì)它的初始化也不行。

(3). decltype()—根據(jù)某個(gè)值推斷類型

? decltype()是和auto同時(shí)出現(xiàn)的,跟auto有點(diǎn)不一樣,decltype()可以填入一個(gè)表達(dá)式,從而表示這個(gè)表達(dá)式的結(jié)果的類型,舉個(gè)例子:

decltype(1) func(int a, int b)
{return a + b;
}
decltype(3.0f) f;

? 用decltype()的好處在于可以只聲明不定義,因?yàn)樽兞康念愋褪且呀?jīng)確定了的,或者就算不確定,也可以通過(guò)其他一系列方式推斷出類型,在編譯器依舊可以確定下來(lái)。

(4). namespace—命名空間

? 命名空間是一個(gè)比較重要的概念,在C語(yǔ)言中我們?cè)?jīng)講過(guò)這么一段示例代碼:

#includeint main()
{int a = 0;
    {int a = 10;
        printf("a = %d\n", a);
    }
    printf("a = %d\n", a);
    return 0;
}

? 結(jié)果是第一行10,第二行0,我就不再演示了,在main()函數(shù)里面的{}括起來(lái)的局部作用域再次定義了一個(gè)變量a,值為10,和main的作用域中的不一樣,在C中我們是沒(méi)有辦法利用這個(gè)局部作用域中的變量的,但是C++擴(kuò)展了這個(gè),給予了我們一項(xiàng)能力:給一個(gè)作用域命名,例如:

namespace ns
{int a = 3;
    int add(int a, int b)
    {return a + b;
    }
}

? 我們可以在一個(gè)命名空間中定義變量與函數(shù)(類也可以,之后再說(shuō)),這樣一來(lái)即便有重名的函數(shù)和變量我們也可以指明他們所在的命名空間來(lái)加以區(qū)別,我們其實(shí)已經(jīng)見(jiàn)過(guò)命名空間了,比如:

std::cout

? 這里的cout這個(gè)std::ostream對(duì)象就是定義在std命名空間中的,有點(diǎn)套娃的那意思了,cout對(duì)應(yīng)的這個(gè)類ostream,也定義在std命名空間中。std是C++的標(biāo)準(zhǔn)命名空間,很多標(biāo)準(zhǔn)庫(kù)中的內(nèi)容都定義在這個(gè)命名空間中,不僅是常用的這些函數(shù)之類的,還有我們之后會(huì)講到的標(biāo)準(zhǔn)模板庫(kù)(STL, Standard Template Library),其中的容器、容器適配器和算法都存放于std命名空間當(dāng)中,關(guān)于STL的內(nèi)容我們之后會(huì)單獨(dú)有幾節(jié)來(lái)講,這是C++中非常重要的一個(gè)部分。

? 這里還要提一個(gè)語(yǔ)法,namespace不僅可以定義命名空間,還可以起別名,例如:

namespace ns
{int a = 0;
}

namespace n = ns;

? 我們之后講到std::filesystem的時(shí)候還會(huì)用到,這里就不多說(shuō)了。

(5). ::—域解析操作符

? 當(dāng)然,我們上一節(jié)沒(méi)有解釋這個(gè)::,其實(shí)我在引言當(dāng)中已經(jīng)說(shuō)了,::叫做域解析操作符,是針對(duì)于命名空間和類的一個(gè)操作符,假設(shè)變量a存在于命名空間ns中:

namespace ns
{int a = 0;
}

? 那么我們可以通過(guò)以下的方式調(diào)用ns中的a:

#includenamespace ns
{int a = 0;
}
int main()
{std::cout<< ns::a<< std::endl;
    ns::a++;
    std::cout<< ns::a<< std::endl;
    return 0;
}

p4

? 是吧,還是很easy的,調(diào)用ns中的其他東西也一樣可以采用::,例如我們的std::cout,就是調(diào)用std命名空間中的名為cout的std::ostream對(duì)象。
? 有的時(shí)候還有人會(huì)這么寫:

#includeint a = 10;
int main()
{std::cout<< ::a<< std::endl;
    return 0;
}

p5

? 簡(jiǎn)單來(lái)說(shuō),前面如果不寫內(nèi)容,就說(shuō)明是從全局命名空間中調(diào)用某變量或某函數(shù)。

(6). using—typedef的C++版本

? 每次打印都要寫std::cout真的會(huì)很不爽,假設(shè)你是一個(gè)OIer或者ACMer,你肯定會(huì)很習(xí)慣輸入這一行語(yǔ)句:

using namespace std;
#1.using + 對(duì)象/函數(shù)/變量;

? using語(yǔ)句是一個(gè)很強(qiáng)的語(yǔ)句,首先可以引入某個(gè)命名空間的函數(shù)與對(duì)象,例如:

#includeusing std::cout;
using std::endl;
int main()
{cout<< "Hello, world!"<< endl;
    return 0;
}

? 這一段代碼也可以打印出Hello, world!,而且不需要再輸入std::了,很方便是吧?

#2.using namespace + 命名空間;

? 這之后就是using namespace句式了,例如之前說(shuō)過(guò)的using namespace std;就是將整個(gè)std命名空間全部引入,這樣的好處是,我們之后用到的所有處于標(biāo)準(zhǔn)命名空間中的內(nèi)容都不需要在加std::了。
? 對(duì)于OIer和ACMer來(lái)說(shuō):這是省時(shí)間的利器,但如果你是寫一個(gè)工程,請(qǐng)一定要慎用,隨意地使用using namespace可能會(huì)導(dǎo)致命名空間污染的出現(xiàn),本身namespace就是避免同名函數(shù)沖突的一種解決方案,舉個(gè)例子,你定義了這么一個(gè)函數(shù):

int max(int a, int b)
{retuan a >b ? a : b;
}

? 同時(shí)還有一個(gè)命名空間n,在其中也有一個(gè)max函數(shù),當(dāng)你編譯運(yùn)行的時(shí)候

#includenamespace n
{int max(int a, int b)
	{return a - b;
	}
}
using namespace n;
using namespace std;
int max(int a, int b)
{return a >b ? a : b;
}
int main()
{auto a = 1, b = 2;
    cout<< max(a, b)<< endl;
    return 0;
}

p6

? VS提示了一些錯(cuò)誤呢,基本上就是說(shuō),在調(diào)用int max這個(gè)函數(shù),且參數(shù)列表是(int, int)的時(shí)候,遇到了好幾個(gè)不同的函數(shù)定義,這樣就引發(fā)了沖突,這就是命名空間污染的一種表現(xiàn)。因此在工程中不要隨便使用using namespace語(yǔ)句!

#3.using A = B;

? using語(yǔ)句的最后一個(gè)用途是和C語(yǔ)言的typedef一樣,給某個(gè)已存在的名字賦一個(gè)別名,當(dāng)然,typedef在C++中也被保留了,你想用也可以,但是真的會(huì)很奇怪,我會(huì)更加建議使用using語(yǔ)句:

typedef unsigned long long size_t;
using size_t = unsigned long long;

? 以上的兩條是一樣的意思,但是看起來(lái)還是using語(yǔ)句會(huì)更直觀一點(diǎn)對(duì)吧,事實(shí)上每次我在寫代碼的時(shí)候如果要用到typedef都要想一想哪個(gè)在前哪個(gè)在后,還是有一點(diǎn)麻煩的。

(7). {}—初始化列表(C++11)

? C++中有很多新的類型,初始化列表就是其中之一,其實(shí)初始化列表這個(gè)東西在C語(yǔ)言中也出現(xiàn)過(guò),就比如:

int a[10] = {1, 2, 3, 4};

? 這個(gè){1, 2, 3, 4}在C++中演變成了初始化列表,是作為C++標(biāo)準(zhǔn)庫(kù)的一個(gè)類型出現(xiàn)的,類型的名字為:

std::initialize_list

? 其中T是一個(gè)模板,不過(guò)你不用知道那么多,它在這里存在的意義就是,任何一個(gè)類型都可以填進(jìn)去,比如對(duì)于{1, 2, 3, 4},它可以是:

std::initialize_list

? 而對(duì)于{1.2, 2.3, 3.4, 4.5},它又可以是:

std::initialize_list

? 總而言之,它不會(huì)受類型限制,我們把這種類叫做模板類,之后在講模板的時(shí)候還會(huì)具體講。我們這里講一些基本的用法就好了。
? 在C++中,現(xiàn)在有四種方式定義變量了:

int a = 1;
int a = {1};
int a{1};
int a(1);

? 在類與對(duì)象的程序設(shè)計(jì)當(dāng)中,前兩種方法會(huì)先根據(jù)參數(shù)表直接調(diào)用構(gòu)造函數(shù),再調(diào)用類的拷貝構(gòu)造函數(shù)(Copy Constructor),而后面兩種則是直接調(diào)用對(duì)應(yīng)參數(shù)表的構(gòu)造函數(shù),后面兩種方法相比前兩種調(diào)用構(gòu)造函數(shù)的次數(shù)更少。這里暫時(shí)不細(xì)講,我們之后在類與對(duì)象部分的構(gòu)造函數(shù)中還會(huì)更加細(xì)致地講解這部分的內(nèi)容。

? 不過(guò)你可能想了,有沒(méi)有這樣一種可能,auto關(guān)鍵字也可以用于以上的初始化方式:

auto a = 1;
auto a = {1};
auto a{1};

? 這里可能要讓你失望了,在C++11中,auto的推導(dǎo)準(zhǔn)則是非常機(jī)械的,對(duì)于前面兩種,規(guī)則很固定,第一個(gè)a的類型為int,第二個(gè)a的類型為std::initializer_list,這個(gè)沒(méi)啥問(wèn)題,關(guān)鍵就在第三個(gè)了,C++11將a的類型也推斷為std::initializer_list,這個(gè)很怪,但是是真的,在C++11中我們不能讓auto和初始化列表同時(shí)出現(xiàn)。
? 這個(gè)問(wèn)題在C++17中得到了解決,auto的推斷機(jī)制變得更加直觀,對(duì)于auto a{1};這樣的寫法,a的類型被推斷為int,同時(shí)在C++11中成立的auto a{1, 2};這樣的寫法在C++17中也變?yōu)檎Z(yǔ)法錯(cuò)誤,當(dāng)然,auto a = {1, 2};是沒(méi)有問(wèn)題的。

? 說(shuō)了這么多,初始化列表的好處是什么呢?初始化列表可以防止數(shù)據(jù)窄化,在利用初始化列表定義變量的時(shí)候,初始化列表內(nèi)的變量類型與變量的類型必須唯一匹配,即類型并非auto的情況下,以下語(yǔ)句是不合法的:

double a{1};

? 除此之外,在類的構(gòu)造函數(shù)中,我們可以使用初始化列表來(lái)接收任意個(gè)數(shù)的參數(shù),這個(gè)之后再講面向?qū)ο蟮臅r(shí)候還會(huì)提到。

(8). &與&&—引用類型 #1.沒(méi)見(jiàn)過(guò)的奇怪表示

? 在C語(yǔ)言中,你見(jiàn)過(guò)以下的表示:

int a;
int* a;
int** a;
int*** a;

? 三重指針可能沒(méi)見(jiàn)過(guò),但是一般就兩種,一般變量和指針。然后有一天你看了一些C++代碼,發(fā)現(xiàn)了這樣的代碼:

int b = 1;
int& a = b;
int&& a = 1;

const int c = 3;
const int& d = c;

? 好怪,不僅有把&寫在類型的位置上的,還有寫&&的。在C語(yǔ)言中&有幾個(gè)用途:取地址(&)、位與(&)和邏輯與(&&),C++中又增加了一種&的用途:引用類型(Reference)。

#2.引用(Reference)的概念

? C++的引用可以理解為通過(guò)另一個(gè)變量對(duì)某一個(gè)變量進(jìn)行引用,比如我們看到以下代碼:

#includeusing std::cout;
using std::endl;
int main()
{auto a{10};
    auto& b{a};
    cout<< "a == b is "<< std::boolalpha<< (a == b)<< endl;
    cout<< "&a = "<< &a<< ", &b = "<< &b<< endl;
    cout<< "a = "<< a<< ", b = "<< b<< endl;
    a++;
    cout<< "a = "<< a<< ", b = "<< b<< endl;
    return 0;
}

p7

? 先解釋一下auto& b{a}; auto關(guān)鍵字雖然能夠進(jìn)行自動(dòng)類型推斷,但不會(huì)推斷出引用類型,因?yàn)檫@樣會(huì)有混淆的問(wèn)題存在,比如auto b{a}; 到底是推斷為引用還是一般變量呢?因此,使用auto推斷引用類型的時(shí)候,一定要加上&。
? 第二個(gè)是std::boolalpha,std::boolalpha可以幫助我們?cè)谑褂胏out打印的時(shí)候顯示出bool類型變量的關(guān)鍵字表示,比如這里a==b的結(jié)果為1,顯示出來(lái)的就是true。
? 接下來(lái)我們就可以看看這段代碼了,b是a的引用,b與a雖然變量名不同,但是地址相同,值相同,對(duì)a做值的更改,b中也會(huì)有相同的更改,這就是引用的大特征,我們可以用引用給一個(gè)變量起“別名”,例如這里的b就是a的別名。

#3.引用的本質(zhì)—指針常量

? 引用的本質(zhì)是指針常量,指針常量 (即T* const) 是:指針變量本身的值(地址)不可變,但地址對(duì)應(yīng)的值可變,例如:

int a = 0;
int* const p = &a;
(*p)++; // 合法,因?yàn)閍不是常量
p++; // 不合法,因?yàn)閜是一個(gè)常量

? 假設(shè)a的地址是0x123,那么p的值只能為0x123,不能變化,但是地址0x123存儲(chǔ)的值可以是任意的。
? 正是因?yàn)橛辛顺A康奶匦?,所以引用類型只能出現(xiàn)在變量定義中,一旦出現(xiàn)就和被引用的變量綁定,直到生存期結(jié)束為止。

#4.左值(lvalue)、將亡值(xvalue)與純右值(prvalue)

? 在C++中的數(shù)據(jù)有左值(lvalue),將亡值(xvalue)和純右值(prvalue) 三種,其中 將亡值(xvalue)和純右值(prvalue)統(tǒng)稱為右值。
? 簡(jiǎn)單來(lái)說(shuō),左值就是可以出現(xiàn)在等號(hào)(賦值操作) 左邊的值,他們都是可以進(jìn)行取地址操作的,例如各種變量(還有字符串字面量)。

? 將亡值的范圍比較抽象:返回右值引用的調(diào)用表達(dá)式以及轉(zhuǎn)換為右值引用的轉(zhuǎn)換函數(shù)的調(diào)用表達(dá)式,關(guān)于將亡值我們?cè)陬惻c對(duì)象的移動(dòng)語(yǔ)義(移動(dòng)構(gòu)造函數(shù))與完美轉(zhuǎn)發(fā)中還會(huì)提到。

? 在這里,簡(jiǎn)單而言,一切不是左值的值都是右值,例如除了字符串字面量之外的所有字面量,通過(guò)構(gòu)造函數(shù)構(gòu)造出的臨時(shí)對(duì)象(沒(méi)有被綁定到某一個(gè)變量上)。

? 提到左右值是因?yàn)橐玫谋举|(zhì)是一個(gè)指針常量,因此我們之前提到的所有引用都是左值引用;對(duì)于右值,按理說(shuō)是取不到地址的,但是C++用了一些特殊的方法來(lái)處理。

#5.常量引用(Const Reference)

? 常量當(dāng)然是可以取到地址的,只是不能修改罷了,常量也屬于左值,那這么一想,我是不是可以這么寫代碼:

const int a = 10;
int& b = a;

? 這一來(lái)b作為a的引用,就可以直接修改a的值了,這很危險(xiǎn)啊,我只要通過(guò)引用就可以修改一個(gè)常量的值了。
? 當(dāng)然不行!這樣的代碼在編譯的時(shí)候是會(huì)報(bào)錯(cuò)的,C++的設(shè)計(jì)者當(dāng)然考慮到了,不過(guò)就這樣直接讓常量不能具備引用,好像也不太好,所以C++中引入了常量引用實(shí)現(xiàn)了對(duì)于常量和字面量的引用。

const int c = 3;
const int& d = c;
const int& e = 1;

? 以上的三條語(yǔ)句都是合法的,這樣就補(bǔ)齊了對(duì)于常量和部分右值的引用。不過(guò)在C++11中,出現(xiàn)了一個(gè)新的語(yǔ)法特性—右值引用,與之對(duì)應(yīng)出現(xiàn)的還有移動(dòng)語(yǔ)義(Move Semantics)和完美轉(zhuǎn)發(fā)(Perfect Forwarding)。

#6.右值引用

? 我們好像在開頭的代碼演示里還有這么一條語(yǔ)句:

int&& a = 1;

? 這個(gè)&&表示的意思就是右值引用,通過(guò)&&我們可以對(duì)一個(gè)右值實(shí)現(xiàn)引用,右值引用允許我們對(duì)右值進(jìn)行一些操作,例如:

#includeusing namespace std;
int main()
{int&& a = 1;
    cout<< a<< endl;
    a++;
    cout<< a<< endl;
    return 0;
}

p9

? 右值引用和常量引用都可以作為非字符串字面量的引用,他們大的區(qū)別在于,右值引用可以對(duì)其進(jìn)行賦值等等操作,而常量引用不行。

#7.傳引用的函數(shù)

? 那這有什么用呢?在C++中出現(xiàn)的引用類型還是相當(dāng)有用的,我記得好像我之前在C語(yǔ)言教程中那兒講swap函數(shù)的時(shí)候就有提到:

void swap(int* a, int* b)
{int* c = *a;
    *a = *b;
    *b = *a;
}

? 還要不停地操作指針,感覺(jué)有點(diǎn)麻煩,有了引用之后,我們可以這么寫:

void swap(int& a, int& b)
{int c = a;
    a = b;
    b = c;
}

? 簡(jiǎn)潔明了,一個(gè)指針都沒(méi)有出現(xiàn),就完成了交換的操作:
p8

? 在調(diào)用這個(gè)函數(shù)的過(guò)程當(dāng)中,兩個(gè)參數(shù)都是以引用的形式傳入的,我們簡(jiǎn)稱為傳引用(Call by Reference),而在C語(yǔ)言中,所以的函數(shù)都是傳值(Call by Value) 的,因此對(duì)于swap函數(shù),在C語(yǔ)言中必須通過(guò)指針完成。
? 引用的出現(xiàn)意義重大,我們可以自行決定一個(gè)函數(shù)是傳值還是傳引,這里要批評(píng)一下python,python中的函數(shù)對(duì)于傳參是傳值還是傳引用有這樣的規(guī)則:簡(jiǎn)單數(shù)據(jù)類型如int,float傳值,復(fù)雜數(shù)據(jù)類型如list,class等就傳引用,雖然python有它的道理,但是實(shí)際應(yīng)用的過(guò)程當(dāng)中還是會(huì)有不小的問(wèn)題,去年年底我們小組在用python做小游戲的時(shí)候就發(fā)現(xiàn)有的函數(shù)會(huì)改變傳入?yún)?shù)的值,后來(lái)才發(fā)現(xiàn)了這個(gè)問(wèn)題。

#8.返回引用的函數(shù)以及一些危險(xiǎn)的操作

? 引用類型也是可以作為函數(shù)的返回類型的,例如:

int& func(int& a)
{return a;
}

? 這個(gè)函數(shù)當(dāng)然做不了什么事情,但是你可以這么用。不過(guò)要注意的是以下兩個(gè)用法是危險(xiǎn)的:

int& func() // 1.返回局部變量的引用
{int b = 10;
    return b;
}

? 這個(gè)用法中返回了func函數(shù)內(nèi)部定義的局部變量b的引用,但是b作為一個(gè)局部變量,在函數(shù)調(diào)用結(jié)束之后是可能會(huì)被釋放掉的,這時(shí)對(duì)b的引用寫入就如同往一個(gè)野指針操作,編譯器不會(huì)報(bào)錯(cuò),只會(huì)有警告。
? 第二個(gè)用法和上一個(gè)其實(shí)類似,但是函數(shù)本身沒(méi)有問(wèn)題:

#includeint func()
{int b = 10;
    return b;
}
int main()
{int& b = func(); // 2.對(duì)返回值取引用
    return 0;
}

? 這次不是警告了,直接編譯不能通過(guò)了,VS中的提示是:非常量引用的初始值必須為左值,這里的func()函數(shù)返回的并非左值,因此我們不能對(duì)func()的返回值使用左值引用 (常量引用和右值引用是可以的),千萬(wàn)不要這么用。

小結(jié)

? 基礎(chǔ)篇的內(nèi)容比較長(zhǎng),因此我分成上下兩篇來(lái)發(fā)布,下篇中會(huì)介紹: cin與cout、constexpr、static_cast()、基于范圍的for循環(huán)、new與delete、nullptr、class和被擴(kuò)充的struct—C++的面向?qū)ο?、函?shù)重載

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧


網(wǎng)站欄目:面向?qū)ο笈cC++基礎(chǔ)—基礎(chǔ)篇(上)-創(chuàng)新互聯(lián)
分享鏈接:http://weahome.cn/article/cspdoj.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部