国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

C++入門篇(2)之引用,內(nèi)聯(lián)函數(shù),auto和范圍遍歷

wangtdgoodluck / 2064人閱讀

前言

承接上文入門篇1,博主這次將會繼續(xù)更新以下內(nèi)容:extern ,引用 ,內(nèi)聯(lián), auto ,范圍for循環(huán) 和 C++中的空指針表示法(溫馨提示:都是講解淺顯的知識,后面會深入講解.),瀏覽此文,大家可以根據(jù)上面的目錄進行定位哦~~

extern “C”

我們知道,在c語言中就只能編譯c寫的程序,但是在C++中卻可以完全兼容c程序,其中緣由就是對于程序的名字修飾規(guī)則不同,將它放在函數(shù)聲明前,便是告訴編譯器要使用c的風格進行編譯,以完成c也可以用c++編寫的函數(shù)庫.

比如谷歌用c++寫的tcmalloc庫中就會提供tcmalloc()和tcfree()來代替c中的malloc()和free()進行提高效率,但是在c中無法使用tcmalloc,為了解決此問題,我們在要是用的函數(shù)前加上extern C就行.

例子:

extern "C" int add(int a,int b);int add(int a,int b){    return a+b;}

小結(jié): 其實該用法更多是在c++中,可能需要將某些函數(shù)按照C的風格來編譯,在函數(shù)前加extern “C”,意思是告訴編譯器,
將該函數(shù)按照C語言規(guī)則來編譯.總之,加上這句話后,無論是c還是c++都可以進行編譯


引用

1.概念

引用的概念不同于指針,引用只是起別名,并未開多的空間,也未創(chuàng)造新東西.比如孫悟空,他可以叫美猴王,但是也有齊天大圣的稱號,而這幾個稱號都是同一個對象.我們?nèi)绻f:“美猴王喜歡姑娘”,那么也就是"齊天大圣喜歡姑娘",本質(zhì)是一個對象.


2.語法

類型& 引用變量名(對象名) = 引用實體; (引用實體的類型必須和&前的類型保持一致哦~~)

int main(){    int a = 10;  //a相當于就是孫悟空    int& b = a;  //b相當于是美猴王    int& c = a;  //c相當于是齊天大圣        b = 100;     //b等于100,相當于美猴王喜歡姑娘(100),那么理所應當?shù)?齊天大圣和孫悟空都會變成100        cout <<"a的值為:"<<a<<endl;    cout <<"b的值為:"<<b<<endl;    cout <<"c的值為:"<<c<<endl;    return 0;}


3.引用特性

  1. 引用在定義時必須初始化

  2. 一個變量可以有多個引用

  3. 引用一旦引用一個實體,再不能引用其他實體

int main(){    int a = 10;          int d = 1000;        int& b = a;  //一旦寫了引用,就必須有完整的實體,不能寫成  int& b;  這是不允許的,即第一條特性    int& c = a;  //a變量被引用了兩次,也就是第二條特性意思        c = d; //這里不再是c是d的別名,而是c變成了1000,因為c已經(jīng)成了a的別名,那么c就永遠只能是a的別名.   第三條特性意思    return 0;}

測試題:

int x = 0,y = 1;int* p1 = &x;int* p2 = &y;int*& p3 = p1;/*********************************************************/*p3 = 10;p3 = p2;

在分割線以前的圖是如下:

請你畫出分割線以后的圖:

?

?

答案:

大家仔細想想為何p3還在p1那里,想想引用的特性哦~~~


4.常量引用

對于常數(shù)來說,無法直接引用,需要使用const,因此叫做常引用,如下:

int a = 10;int& a1 = a;   //正常引用,沒問題const int b = 10;int& a2 = b;   //引用失敗,因為b是常數(shù),無法int引用const int& a3 = b;  //成功引用;int& a4 = 100; //引用失敗,因為100是常數(shù),無法int引用const int& a5 = 100;  //成功引用

所以,有人總結(jié)出想使用引用的條件是:可以縮小讀寫權(quán)限,但不能放大讀寫權(quán)限.

根據(jù)以上特性,在實際運用中,引用一般有什么意義呢?

答曰:

  • 函數(shù)傳參時,可以減少傳參拷貝(引用作用)
  • 函數(shù)傳參時,可以保護形參不被修改(常量引用作用)
  • 函數(shù)傳參時,既可以接收變量,又可以接收常量(常量引用作用).

針對特性一例子:

struct node   //某個結(jié)構(gòu)體定義如下:{    int val;    char left;    int right;    struct node* next;};void modify(struct node& node0)  //某函數(shù)定義如下:  如果其參數(shù)設(shè)置為引用,將不需要通過函數(shù)傳遞方式中的值傳遞(拷貝),造成空間消耗巨大.{    //此處省略相關(guān)操作....}int main(){    struct node Node;    modify(Node);    return 0;}

針對特性二和特性三例子:

如果一個函數(shù)在執(zhí)行相關(guān)操作中,只是需要訪問參數(shù)的值,并不需要修改參數(shù),那么可以用常量引用.

int add(const int& a,const int& b){    return a+b;  //比如加法函數(shù),如果手誤,碼碼錯代碼,修改了a或b的值,編譯器會自動提示.}int main(){    int a = 10;    int b = 20;    cout<<"變量作為實參"<<add(a,b)<<endl;    cout<<"常量作為實參"<<add(10,20)<<endl;   //如果函數(shù)形參不寫成引用,將無法接收常量.    return 0;}

5.引用做函數(shù)返回值

當引用做函數(shù)返回值時候,返回的是一個指向返回值的隱私指針.這樣,函數(shù)就可以放在賦值語句的左邊。例如,請看下面這個簡單的程序:

#include using namespace std;double vals[] = {10.1, 12.6, 33.1, 24.1, 50.0};double& setValues(int i) {     double& ref = vals[i];       return ref;   // 返回第 i 個元素的引用,ref 是一個引用變量,ref 引用 vals[i]}// 要調(diào)用上面定義函數(shù)的主函數(shù)int main (){   cout << "改變前的值" << endl;   for ( int i = 0; i < 5; i++ )   {       cout << "vals[" << i << "] = "<< vals[i] << endl;   }       setValues(1) = 20.23; // 改變第 2 個元素   setValues(3) = 70.8;  // 改變第 4 個元素           cout << "改變后的值" << endl;   for ( int i = 0; i < 5; i++ )   {		cout << "vals[" << i << "] = "<< vals[i] << endl;   }   return 0;}

結(jié)果:

注意點:

當引用作為函數(shù)返回值時,被引用的對象其作用域必須是有效范圍,所以返回一個對局部變量的引用是不合法的,但是,可以返回一個對靜態(tài)變量的引用.

int& func() {   int a = 100;   // return a; // 錯誤的引用返回   static int x;   return x;     // 安全,x 在函數(shù)作用域外依然是有效的}

6.引用注意點

我們看下面這個例子:

int i = 10;double b = i;         //可以編譯成功double& c = i;        //報錯,因為引用實體類型和引用類型必須一致const double& d = i;  //成功,原因是 i到 d過程中,會先產(chǎn)生一個臨時空間,然后把i的值放到臨時空間中,又由于臨時空間具有常性,所以加上const就成功

7.傳值、傳引用效率比較

以值作為參數(shù)或者返回值類型,在傳參和返回期間,函數(shù)不會直接傳遞實參或者將變量本身直接返回,而是
傳遞實參或者返回變量的一份臨時的拷貝,因此用值作為參數(shù)或者返回值類型,效率是非常低下的,尤其是
當參數(shù)或者返回值類型非常大時,效率就更低

#include #include using namespace std;struct A { int a[10000]; };void TestFunc1(A a) {}void TestFunc2(A& a) {}int main(){	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();	// 分別計算兩個函數(shù)運行結(jié)束后的時間	cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;	cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;	return 0;}

#include #include using namespace std;struct A { int a[10000]; };A a;A TestFunc1() { return a; }A& TestFunc2() { return a; }int main(){	// 以值作為函數(shù)返回值	size_t begin1 = clock();	for (size_t i = 0; i < 10000; ++i)		TestFunc1();	size_t end1 = clock();	// 以引用作為函返回值	size_t begin2 = clock();	for (size_t i = 0; i < 10000; ++i)		TestFunc2();	size_t end2 = clock();	// 分別計算兩個函數(shù)運行結(jié)束后的時間	cout << "A TestFunc1()-time:" << end1 - begin1 << endl;	cout << "A& TestFunc2()-time:" << end2 - begin2 << endl;	return 0;}

通過上述代碼的比較,發(fā)現(xiàn)傳值和引用在作為傳參以及返回值類型上效率相差很大


內(nèi)聯(lián)函數(shù)

1.概念

一種通過inline修飾的函數(shù),編譯器進行編譯時可以直接在函數(shù)調(diào)用的地方進行展開,不需要多余的函數(shù)棧幀開銷,節(jié)約了時間

普通函數(shù)調(diào)用:

通過右邊的匯編代碼可以看到,調(diào)用add函數(shù)需要call命令,說明消耗了棧幀空間.


內(nèi)聯(lián)函數(shù)調(diào)用

可以用過右邊的匯編代碼看到,調(diào)用add函數(shù)時候,是直接展開add內(nèi)容進行使用的,并未進行專門的函數(shù)調(diào)用.


因此,內(nèi)聯(lián)函數(shù)可以提升效率.其實本質(zhì)上來說,C++的內(nèi)聯(lián)函數(shù)特性就是為了解決C語言中 宏 的書寫麻煩.也就是說,內(nèi)聯(lián)的出現(xiàn)是為了替代宏.


2.特性

  1. inline是一種以空間換時間的做法,省去調(diào)用函數(shù)額外開銷。所以代碼很長或者有循環(huán)或者遞歸的函數(shù)不適宜使用作為內(nèi)聯(lián)函數(shù) .
  2. inline對于編譯器而言只是一個建議,如果定義為inline的函數(shù)體內(nèi)有循環(huán)/遞歸等,編譯器會自動優(yōu)化,并忽略掉內(nèi)聯(lián).

比如下面情況,就是說的上面兩種特性:

int accumulate(int n){    int ans = 0;    for(int i = 1;i<=n;i++)    {        ans += i;    }    return  ans;}
  1. inline建議聲明和定義不可分離,分離會導致鏈接錯誤。因為inline被展開,就沒有函數(shù)地址了,鏈接就會找不到.

比如下面這種情況:

// F.h    頭文件的內(nèi)容#include using namespace std;inline void f(int i);// F.cpp  源文件的內(nèi)容#include "F.h"void f(int i){	cout << i << endl;}// main.cpp#include "F.h"int main(){	f(10);	return 0;}

此時編譯器便會顯示鏈接錯誤


auto關(guān)鍵字

1.概念

一個新的類型指示符,auto聲明的變量必須由編譯器在編譯時期推導而得.

#include using namespace std;int main(){    int a = 10;    int b = 20;    double c = 12.12;    double d = 12.13;        auto e = a + b;      //e 的類型是int,編譯器會自行推導    auto f = c + d;      //f 的類型是double,編譯器會自行推導    return 0;}

2.auto的使用細則

auto與指針和引用結(jié)合起來使用:
用auto聲明指針類型時,auto和auto*沒有任何區(qū)別,但用auto聲明引用類型時則必須加&

int main(){	int x = 10;	auto a = &x;          //auto的類型是 int*	auto* b = &x;         //auto的類型是 int*	auto& c = x;          //auto的類型是 int	cout << typeid(a).name() << endl;	cout << typeid(b).name() << endl;	cout << typeid(c).name() << endl;    *a = 20;	*b = 30;	 c = 40;	return 0;}

在同一行定義多個變量
當在同一行聲明多個變量時,這些變量必須是相同的類型,否則編譯器將會報錯,因為編譯器實際只對
第一個類型進行推導,然后用推導出來的類型定義其他變量

void TestAuto(){	auto a = 1, b = 2;	auto c = 3, d = 4.0; // 該行代碼會編譯失敗,因為c和d的初始化表達式類型不同}

3.auto不能推導的場景

auto不能作為函數(shù)的參數(shù),不能直接用來聲明數(shù)組.

void TestAuto(auto c){	int a[] = {1,2,3};	auto b[] = {4,5,6};}

基于范圍的for循環(huán)(C++11)

在C++98中如果要遍歷一個數(shù)組,可以按照以下方式進行:

void TestFor(){	int array[] = { 1, 2, 3, 4, 5 };	for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)		cout << array[i]<<" ";}

對于一個有范圍的集合而言,像上面這樣,由程序員來說明循環(huán)的范圍是多余的,有時候會容易犯錯誤。因此C++11中引入了基于范圍的for循環(huán)。for循環(huán)后的括號由冒號:分為兩部分:第一部分是范圍內(nèi)用于迭代的變量,第二部分則表示被迭代的范圍

void TestFor(){    int array[] = { 1, 2, 3, 4, 5 };    for(auto& e : array)    	e *= 2;          //通過引用,改變值    for(auto e : array)    	cout << e << " ";  //挨個輸出}

使用條件

范圍for的使用條件,必須確定明確范圍

  • 對于數(shù)組而言,就是數(shù)組中第一個元素和最后一個元素的范圍
  • 對于類而言,應該提供begin和end的方法,begin和end就是for循環(huán)迭代的范圍
void TestFor(int array[])   //這種接收方式,本質(zhì)上是指針,所以下面的范圍遍歷便不適用,因為沒有明確的范圍標志.{	for(auto& e : array)		cout<< e <<endl;}


指針空值nullptr

在良好的C/C++編程習慣中,聲明一個變量時最好給該變量一個合適的初始值,否則可能會出現(xiàn)不可預料的錯誤,比如未初始化的指針。如果一個指針沒有合法的指向,我們基本都是按照如下方式對其進行初始化:

void TestPtr(){	int* p1 = NULL;	int* p2 = 0;}

而NULL實際是一個宏,在傳統(tǒng)的C頭文件(stddef.h)中,可以看到如下代碼:

#ifndef NULL#ifdef __cplusplus#define NULL 0#else#define NULL ((void *)0)#endif#endif

可以看到,NULL可能被定義為字面常量0**,或者被定義為無類型指針**(void*)的常量。不論采取何種定義,在使用空值的指針時,都不可避免的會遇到一些麻煩,比如下面的重載函數(shù):

void f(int x){	cout<<"f(int)"<<endl;}void f(int* x){	cout<<"f(int*)"<<endl;}int main(){	f(0);	f(NULL);	f((int*)NULL);       //大家現(xiàn)在猜猜結(jié)果會是啥?	return 0;}
																 ![image-20211009204652154](https://img-blog.csdnimg.cn/img_convert/702a3c6fbdfa5bafe397fe8f7dc085da.png)

驚不驚喜,意不意外?我們傳參NULL時候,本意是想調(diào)用第二個函數(shù),但是編譯器卻認為我們想要調(diào)用第一個函數(shù),這就是在C語言中使用NULL的缺陷,因此,C++提出了nullptr代替NULL

注意事項:

  1. 在使用nullptr表示指針空值時,不需要包含頭文件,因為nullptr是C++11作為新關(guān)鍵字引入的
  2. 為了提高代碼的健壯性,在后續(xù)表示指針空值時建議最好使用nullptr
  3. 在C++11中,sizeof(nullptr) 與 sizeof((void*)0)所占的字節(jié)數(shù)相同

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/122192.html

相關(guān)文章

  • C++】初窺門徑---入門

    摘要:在大型的工程中,自己定義的變量函數(shù),類名與其他人定義的相沖突等問題。使用標準輸出控制臺和標準輸入鍵盤時,必須包含頭文件以及標準命名空間。缺省參數(shù)概念缺省參數(shù)是聲明或定義函數(shù)時為函數(shù)的參數(shù)指定一個默認值。 目錄 前言 1.命名空間 1.1命名空間定義 1.2 命名空間使用 2. C++的輸入和...

    不知名網(wǎng)友 評論0 收藏0
  • C++C++快速入門

    摘要:中包含的即為命名空間的成員。使用輸入輸出更方便,不需增加數(shù)據(jù)格式控制,比如整形,字符可以連續(xù)輸出,表示換行缺省參數(shù)備胎,就是給汽車準備一個備用輪胎,一旦那個輪子爆胎或者出了問題,備用輪胎就方便及時地取而代之,汽車就不至于中途拋錨。 ...

    TalkingData 評論0 收藏0
  • 系統(tǒng)地學習C++

    摘要:本書主要圍繞一系列逐漸復雜的程序問題,以及用以解決這些問題的語言特性展開講解。你不只學到的函數(shù)和結(jié)構(gòu),也會學習到它們的設(shè)計目的和基本原理。因此我們把精力集中在最有價值的地方。本書不僅是對模板的權(quán)威解釋,而且本書還深入地介紹了其他一般的思想。 C++ 入門教程(41課時) - 阿里云大學 C+...

    joyqi 評論0 收藏0
  • C++從0到1】新手都能看懂的C++入門(上),建議收藏

    摘要:上面這三種均不造成重載,現(xiàn)在來說明原因。結(jié)論對于引用返回,返回的對象必須是棧幀銷毀后還存在的。全局,靜態(tài),未銷毀的函數(shù)棧幀當中的都是可以的指針與引用如圖兩者底層實現(xiàn)差不多,引用是用指針模擬的。不建議聲明和定義分離,分離會導致鏈接錯誤。 ...

    xcold 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<