外匯期貨喊單網(wǎng)站怎么做的網(wǎng)絡(luò)營銷產(chǎn)品策略
6.?引用(引用就是取別名)
6.1?引用的概念和定義
引用不是新定義一個變量,而是給已存在變量取了?個別名,編譯器不會為引用變量開辟內(nèi)存空間,它和它引用的變量共用同一塊內(nèi)存空間。比如:水滸傳中李逵,宋江叫"鐵牛",江湖上人稱"黑旋風(fēng)";林沖,外號豹子頭;
類型& 引用別名 = 引用對象;
C++中為了避免引入太多的運(yùn)算符,會復(fù)用C語言的?些符號,比如前面的<< 和 >>,這里引用也和取地址使用了同?個符號&,大家注意使用方法角度區(qū)分就可以。
?int a = 0;
// 引?:b和c是a的別名
int& b = a;
int& c = a;
// 也可以給別名b取別名,d相當(dāng)于還是a的別名
int& d = b;
這串代碼在底層的角度是這樣的?
對指針變量取別名:
int* p1 = &a;?
int*& p2 = p1;
?指針變量的使用:?
typedef struct ListNode
{
? ?int val;
? ?struct ListNode* next;
}LTNode, *PNode;
int main()
{
? ?PNode plist = NULL;
? ?ListPushBack(plist, 1);
? ?return 0;
}
?這里的*PNode是指把typedef struct ListNode* 定義為PNode。
6.2?引用的特性



這里的d的地址沒變,說明d還是a的別名,d沒有指向e,只是把e的值賦給了d。
當(dāng)我們實現(xiàn)鏈表的時候,我們要刪除一個結(jié)點,但這時的地址之間是相互關(guān)聯(lián)的,因為引用不能改變指向,所以就不可能完成。所以C++的指針引用不能完全替代指針。
6.3?引用的使用

減少拷貝的案例:
傳值傳參會生成一個拷貝,傳值返回也會生成一個拷貝。C++中是這樣規(guī)定的,在紅線這里進(jìn)行一個傳值返回,返回這個對象的時候,?他不會引用這個對象做函數(shù)調(diào)用的返回值,不會返回要返回的東西,它會生成一個臨時對象,把這的值給臨時變量,再用臨時變量做這個整個表達(dá)式的返回值。STTop(st1)+=1;這是的加1就是加到臨時對象上面。臨時對象具有常性。
那臨時對象是什么呢?
臨時變量通常是指編譯器在棧里面臨時開一塊空間存儲中間值的這種,也有可能是用寄存器去存。
這里如何使用STTop(st1)+=1呢?只需要采用引用返回就可以了。傳引用返回就是返回他的別名,也就是這里的2。也就a數(shù)組指向的top-1這里的對象。這時候就把引用對象給改變了。
typedef int STDataType;
typedef struct Stack
{
?? ?STDataType* a;
?? ?int top;
?? ?int capacity;
}ST;void STInit(ST& rs, int n = 4)
{
?? ?rs.a = (STDataType*)malloc(n * sizeof(STDataType));
?? ?rs.top = 0;
?? ?rs.capacity = n;
}// 棧頂
void STPush(ST& rs, STDataType x)
{
?? ?// 滿了, 擴(kuò)容
?? ?if (rs.top == rs.capacity)
?? ?{
?? ??? ?printf("擴(kuò)容\n");
?? ??? ?int newcapacity = rs.capacity == 0 ? 4 : rs.capacity * 2;
?? ??? ?STDataType* tmp = (STDataType*)realloc(rs.a, newcapacity *
?? ??? ??? ?sizeof(STDataType));
?? ??? ?if (tmp == NULL)
?? ??? ?{
?? ??? ??? ?perror("realloc fail");
?? ??? ??? ?return;
?? ??? ?}
?? ??? ?rs.a = tmp;
?? ??? ?rs.capacity = newcapacity;
?? ?}
?? ?rs.a[rs.top] = x;
?? ?rs.top++;
}
int& STTop(ST& rs)
{
?? ?assert(rs.top > 0);?? ?return rs.a[rs.top - 1];
}
int main()
{
?? ?ST st1;
?? ?STInit(st1);
?? ?STPush(st1, 1);
?? ?STPush(st1, 2);
?? ?cout << STTop(st1) << endl;
?? ?//修改棧頂?shù)臄?shù)據(jù)呢
?? ?(STTop(st1)) += 1;
?? ?cout << STTop(st1) << endl;
?? ?return 0;
}
?其實指針也可以做到:
并不是任何場景都能用引用返回(后面結(jié)合類和對象講),比如說:
ret是局部變量,這里類似于野引用。
int* fun( )
{
? ? ?int ret = 10;
? ? ?return *ret;
}
這里的指針就越界了,指針越界不一定報錯。?
?
在vs中設(shè)置了抽查位置,這兩個位置不分配給別人,給兩個固定的值,在程序運(yùn)行結(jié)束時看這兩個位置的值有沒有發(fā)生改變,沒有被修改就說明沒有越界。?
6.4?const引用
?這里是把x的這塊空間拷貝給給y,x不能修改這塊空間。
下面這個也是經(jīng)典的權(quán)限放大:
下圖這個是權(quán)限的縮小:?
p1對于a的權(quán)限是只讀不能寫的,p1拷貝給給p2,p2又變成可讀可寫的了,p2的權(quán)限被放大,p5指向b的權(quán)限是可讀可寫的,p6指向p5也是可讀可寫的(這里不存在權(quán)限放大,因為const修飾的是p5本身不是指向的內(nèi)容)。?
a * 3這里存在一個臨時變量,臨時變量具有常性,這里加個const就行了。
這里的d給給rd其實也不是直接給過去的,中間也會產(chǎn)生一個臨時變量來存儲中間的結(jié)果。d給給中間的臨時對象,這個臨時對象是int類型,臨時對象再給給rd。
類型轉(zhuǎn)換會產(chǎn)生臨時對象,d給了臨時對象,這里的臨時對象給給rd。也就是說rd引用了臨時對象。
那上面這些到底有什么用呢?
這里的傳值傳參就不說了,對于引用傳參
void fun(int& rx)如果變量 rx 不改變形參,建議前面加 const,void fun(const int& rx),加const的好處是什么呢?傳參就非常寬泛。
const引用的價值是什么?
1.可以引用const對象?
2.可以引用普通對象
3.可以引用臨時對象
6.5?指針和引用的關(guān)系

野引用的案例:?
從底層匯編的角度看,引用也是用指針實現(xiàn)的。?
?
7.?inline

可執(zhí)行程序是一個文件,它會以一個進(jìn)程的角度來進(jìn)行運(yùn)行(可執(zhí)行程序會生成一個進(jìn)程),進(jìn)程才會給它分配內(nèi)存,進(jìn)程會把可執(zhí)行程序的那個指令加載到內(nèi)存的里面。
10000*100是指10000行指令*100行Add的指令總和的指令,10000+100是指10000行指令+100行Add的指令總和的指令。內(nèi)聯(lián)展開會導(dǎo)致一個問題:代碼膨脹,代碼膨脹會導(dǎo)致可執(zhí)行程序變大,可執(zhí)行程序變大,加載到進(jìn)程也會變大,加載到內(nèi)存導(dǎo)致內(nèi)存變大。(可執(zhí)行程序就是安裝包)
// F.h# include <iostream>using namespace std;inline void f ( int i);// F.cpp# include "F.h"void f ( int i){cout << i << endl;}// text.cpp# include "F.h"int main (){
// 鏈接錯誤:?法解析的外部符號 "void __cdecl f(int)" (?f@@YAXH@Z)f ( 10 );return 0 ;}//那要怎么做呢?把// F.cpp這個文件中的f(int i)給注釋掉# include "F.h"//void f ( int i)//{//cout << i << endl;//}在// F.h中定義inline void f ( int i){cout << i << endl;}
?// 實現(xiàn)?個Add宏函數(shù)的常見問題
//#define Add(int a, int b) return a + b;//#define Add(a, b) a + b;//#define Add(a, b) (a + b)// 正確的宏實現(xiàn)(宏本質(zhì)是一種替換)//宏函數(shù)坑很多,但是由于替換機(jī)制,調(diào)用函數(shù)時不用建立函數(shù)棧幀,能做到提效的作用。# define Add(a, b) ((a) + (b))// 為什么不能加分號 ?int main(){int ret = Add(1,2);//這里是將a替換成1,b替換成2;//int ret = Add(1,2);;//在這種場景下不會有問題cout? <<? Add(1,2)? <<? endl;//如果加分號在這種情況下就會報錯,還有下面這種if(Add(1,2)){//...}cout? <<? ret? <<? endl;}// 為什么要加外?的括號 ?//有下面這種情況int main(){int ret = Add(1,2);//這里是將a替換成1,b替換成2;//int ret = Add(1,2);;cout? <<? Add(1,2)*3??<<? endl;//cout? <<? (1)? +? (2) * 3? <<? endl;}// 為什么要加里面的括號 ?int main(){int x =1,y = 2;Add(x?&?y ,x | y);? // ->? (x & y + x | y)}
8.?nullptr
#ifndef NULL
????????#ifdef __cplusplus
????????????????#define NULL 0//C++
????????#else
????????????????#define NULL ((void *)0)//C語言
????????#endif
#endif

? C++11中引入nullptr,nullptr是?個特殊的關(guān)鍵字,nullptr是?種特殊類型的字?量,它可以轉(zhuǎn)換 成任意其他類型的指針類型。使用nullptr定義空指針可以避免類型轉(zhuǎn)換的問題,因為nullptr只能被 隱式地轉(zhuǎn)換為指針類型,而不能被轉(zhuǎn)換為整數(shù)類型。
?