1. 程式人生 > >【C++】函式引用

【C++】函式引用

概念:

引用不是新定義一 個變數,而是給已存在變數取了一個別名,編譯器不會為引用變數開闢記憶體空間,它和它引用的變數共用同一塊記憶體空間。

用法:

型別&  引用變數名(物件名) =引用實體;

void Test()
{
    int a=10;
    int& ra = a;//定義引用型別(相當於ra是a的別名)

    printf("%p\n"。&a);
    printf("%p\n",&ra);
}

注意: 引用型別必須和引用實體是同種型別的

引用特性:

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

int main()
{
    int a = 10;
    int& ra ;//不進行初始化,程式碼編譯時出錯

2.一個變數可以有多個引用(還可以給別名取別名);

#include <stdio.h>
#include <stdlib.h>
#include <iostream>

int main()
{
	int a = 10;
	int& ra = a;//定義引用型別(相當於ra是a的別名)
	int& qa = ra;

	printf("%p\n",&a);
	printf("%p\n",&ra);
	printf("%p\n", &qa);
	system("pause");
	return 0;
}

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

int main()
{
	int a = 10;
	int& ra = a;//定義引用型別(相當於ra是a的別名)
	int b = 0;
	int& ra = b;

	printf("%p\n",&a);
	printf("%p\n",&ra);
	printf("%p\n", &ra);
	system("pause");
	return 0;
}
//該程式碼編譯時出錯,因為ra既引用了a,又引用了b

常引用

void testRef()
{
	const int a = 10;
	int& ra = a;//該語句編譯時會出錯,a為常量
	const int& ra = a;//正確
	
	int b=10;//該語句編譯時會出錯,a為常量
	const int& b = 10;////正確

	int i = 10;
	double& rd =i;//該語句編譯時會出錯,型別不同
	const double& rd = i;//正確

}
int main()
{
	testRef();
	system("pause");
	return 0;
}

其中:

int i = 10;
double& rd =i;//該語句編譯時會出錯,型別不同

這個程式碼出錯的真正原因並不是因為型別,而是因為在隱式轉換中,會生成臨時變數,而臨時變數是由編譯器生成的,具有常屬性,不能被修改,而rd也就相當於給這個臨時變數起別名,所以只有加上const時,程式碼才能執行通過。

引用時,對許可權有一個要求:許可權只能縮小,不能放大,比如:

void testRef()
{
	const int a = 10;
	int& b = a;

}

此時這個別名是取不出來的,因為型別匹配不上,a是const int型別,也就是說a是不能被改變的,b變成a的別名,b的型別是int,意味著b可以被修改,相當於a的許可權被擴散化(修改),所以不能這樣。加上const就可以了。

void testRef()
{
    const int a = 10;
    const int& b = a;

}

許可權擴大化不可以,但是縮小又是可以的,如:

void testRef()
{
    int c = 20;
    const int& d = c;

}

這個是正確的,c是可讀可修改,給d後,可讀但不修改。

引用作用:

1.做引數(效率高)

void Swap(int& left, int& right)
{
	int tmp = left;
	left = right;
	right = tmp;
}

2.做返回值(相當於少開闢一個空間,效率高)

int& TestRef(int& a)
{
	a += 10;
	return 0;
}

傳值和傳引用的效率比較

以值作為引數或者返回值型別,在傳參和返回期間,函式不會直接傳遞實參或者將變數本身直接返回,而是傳遞實參或者返回變數的一份臨時拷貝,因此用值作為引數或返回值型別,效率是非常低下的,尤其是當引數或者返回值型別非常大時,效率就更低。那指標和引用作為引數和返回值型別的效率呢?

(1)指標和引用作為引數的效能比較

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <time.h>
using std::cout;
using std::endl;

struct A
{
	int a[100000];
};
void TestFunc1(A* a)//指標
{

}
void TestFunc2(A& a)//引用
{

}

void TestRefAndPtr()//
{
	A a;
	//以指標作為函式引數
	size_t begin1 = clock();
	for (size_t i = 0; i < 100000; i++)
		TestFunc1(&a);
	size_t end1 = clock();
	//以指標作為函式引數
	size_t begin2 = clock();
	for (size_t i = 0; i < 100000; i++)
		TestFunc2(a);
	size_t end2 = clock();
	//分別計算兩個函式執行結束後的時間
	cout << "TestFunc1(int*)-time:" << end1 - begin1 << endl;
	cout << "TestFunc2(int&)-time:" << end2 - begin2 << endl;

}
//執行多次,檢測指標和引用在傳參方面的效率差別
int main()
{
	for (int i = 0; i < 10; i++)
	{
		TestRefAndPtr();
	}
	system("pause");
	return 0;
}

很明顯,引用要比指標效率更高一些:

(2)指標和引用作為返回值型別的效能比較

//作為返回值型別的效能比較
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <time.h>
using std::cout;
using std::endl;

struct A
{
	int a[100000];
};
A a;
A* TestFunc1()//指標
{
	return &a;
}
A& TestFunc2()//引用
{
	return a;
}

void TestRefAndPtr()//
{

	//以指標作為函式引數
	size_t begin1 = clock();
	for (size_t i = 0; i < 10000000; i++)
		TestFunc1();
	size_t end1 = clock();
	//以指標作為函式引數
	size_t begin2 = clock();
	for (size_t i = 0; i < 10000000; i++)
		TestFunc2();
	size_t end2 = clock();
	//分別計算兩個函式執行結束後的時間
	cout << "TestFunc1-time:" << end1 - begin1 << endl;
	cout << "TestFunc2-time:" << end2 - begin2 << endl;

}
//執行多次,檢測指標和引用在傳參方面的效率差別
int main()
{
	TestRefAndPtr();
	system("pause");
	return 0;
}

顯而易見:依舊是引用的效率高

引用和指標的區別:

在語法概念上,引用就是一個別名,沒有獨立空間,和其引用實體共用一塊空間。(概念上來說,引用是別名,而指標是地址。引用概念上雖然不是存地址,但是在底層,還是用存地址的方式實現的)

  引用和指標的不同點:

      1.引用在定義時必須初始化,指標沒有要求

      2.引用在初始化時引用一個實體後,就不能再引用其他實體,而指標可以在任何時候指向任何一個同類型實體

      3.引用沒有NULL引用,但指標有NULL指標

      4.在sizeof中含義不同:引用結果為引用型別的大小,但指標始終是地址空間所佔位元組個數(32位平臺下佔4個位元組)

      5.引用自加即引用的實體增加1,指標自加即指標向後偏移一個型別的大小6.有多級指標,但是沒有多級引用

      7.訪問實體方式不同,指標需要顯式解引用,引用是編譯器自己處理

      8.引用比指標使用起來相對更安全

問題:如何定義一個8位元組的指標?

控制一個64位的編譯器即可(把編譯器修改為64位的)。