天天看點

const 與引用、指針、形參結合

  • 引用:引用(&)與類型結合在一起,相當于給變量起别名,(引用不參與類型)底層以指針的方式來支援使用,在引用使用的地方,系統自帶解引用的過程。

例:

 int a=10;

int &b=a;//給變量a起别名叫b, 相當于int *b=&a;b也要開辟記憶體,因為底層實作時p是一個指針

b=20; //自帶解引用                  相當于*b=20;

引用的注意事項:

一.引用一定要初始化

例 :int &a; 錯誤

二.引用所引用的變量一定要能取位址

例;

int a=10;

int &b=a; //正确

int &c=10;// 錯誤,因為底層用指針支援,相當于 int *c=&10 ,這是錯誤的

三.引用不可改變

例:

#include<iostream>
using namespace std;
int main()
{
	int a=10;
	int b=20;
	int &c=a;
	 c=b;
	c=100;

	cout<<a<<endl;
	cout<<b<<endl;
	return 0;
}
           

結果:

const 與引用、指針、形參結合

可見當改變c的指向後指派,結果改變原指向的變量的資料

四.隻能通路引用變量所引用的記憶體塊的内容

因為所有用到引用的地方自帶解引用

不能傳回局部變量的位址或引用

例:

int &get()
{
	int tmp=10;
	return tmp;
}

int main()
{
	
	int rt1=get();
	cout<<rt1<<endl;
	int &rt2=get();
	cout<<rt2<<endl;
	return 0;
}
           

結果:

const 與引用、指針、形參結合

發現結果符合我們的需求,如果在 int &rt2=get()函數後調用其他函數呢?

int &get()
{
	int tmp=10;
	return tmp;
}
void set()
{}
int main()
{
	
	int rt1=get();
	cout<<rt1<<endl;
	int &rt2=get();
	set();
	cout<<rt2<<endl;
	return 0;
}
           

我們隻在 int &rt2=get()函數後調用set()函數,rt2的數值就發生了改變,可見傳回局部變量的引用并不安全

因為函數傳回了局部變量的位址, int &rt2=get()是給局部變量tmp的位址起别名rt2,在get()函數清棧後,我們又調用了set()函數,set()函數開棧時會初始化記憶體,将tmp的位址的記憶體資料修改,導緻rt2通路資料時出錯。

  • const 和引用結合

常引用引用的變量可以不能取位址

例: int &a=10; //錯誤,

const int &a=10;//正确

因為先将10存放到臨時量的記憶體中,常引用a引用臨時量的記憶體單元

内置類型生成的臨時量是常量(不能被修改)

例:

int a=10;

int *&p=&a; //錯誤,因為&a(a的位址)是常量

改為:int * const &p=&a;//正确

  • const 和**(const 和指針結合主要防止間接通路修改常量記憶體塊的值)

例:

int a=10;
int *p=&a;
const int**q=&p;//錯誤
           
const 與引用、指針、形參結合

因為第四行const int **q=p;

const 修飾的變量是**q ,類型是int 

相當于a是常量

直接通路 a

間接通路 *p, **q, *(*q)==*p

const 修飾**q 可以通過*p或 *(*q)修改a的值

用const修飾*p或*q即可避免錯誤

int a=10;
int *p=&a;
int  const *const*q=&p;
           

避免通過**q或*(*q)來間接通路修改常量記憶體塊a的值,但可以通過p間接通路修改a的值(*p=20)

但const 定義在第三行,隻看第三行和其以下的代碼是否會修改常量記憶體塊的值,并不關心const定義上方的變量間接通路是否會修改常量記憶體塊的值。

int a=10;
const int *p=&a;
const int **q=&p;
           

避免通過*p,**q,*(*q)來間接通路修改常量記憶體塊a的值

  • const和形參結合

一.防止實參被修改

例:

int add(int *a,int *b)
{
	 *a=20;
	 return *a+*b;
}
int main()
{
	int a=10;
	int b=20;
	cout<<add(&a,&b)<<endl;
	cout<<a<<endl;
	cout<<b<<endl;
	return 0;
}
           

add()函數隻是為了計算a+b的值,并不修改a和b的值,但函數中卻修改了a的值,為了避免函數修改實參,給形參加上const

即 int add(const int*a,const int *b)

二.接收臨時量

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

int main()
{
	int a=10;
	int b=20;
	swap(a,b);
	cout<<a<<endl;
	cout<<b<<endl;
	return 0;
}
           

上面代碼中swap()函數實作了兩個數的交換功能,但如果直接調用swap(10,20)時,程式崩潰,

因為int &a=10,int &b=20,不符合引用的規則(引用引用的變量一定要能取位址)

為了解決這個問題改為常引用,即 void swap(const int &a,const int &b)

當直接調用swap(10,20)時,先将20存放到臨時量中,再将臨時量的位址賦給b,再将10存放到臨時量中,再将臨時量的位址賦給a

繼續閱讀