C++中引用和匿名物件的理解和本質剖析

沙米筆記發表於2016-04-13

大家對C++的引用應該都不陌生吧,抱著既要知其然,也要知其所以然的態度。下面將按照是什麼?怎麼用?為什麼需要?本質剖析的流程來向大家一一描述。

引用是什麼?

引用其實就是給變數起的一個別名,使用這個別名跟使用變數名沒有區別。

那什麼又是變數名呢?

變數名實質上是一段連續儲存空間的別名,是一個標號(門牌號),編譯器通過變數來申請並命名記憶體空間,程式設計師可以通過變數的名字可以使用儲存空間。

也可以這樣理解,變數名是邏輯概念,變數是物理層面,變數含資料型別和資料值,資料型別決定記憶體的分配,編譯器將變數名和變數對應的記憶體聯絡起來,使程式設計師可以通過變數名來操作記憶體。

引用怎麼用?

語法:Type& name = var;

規則:1、普通引用在宣告時必須用其它的變數進行初始化

2、引用作為函式引數宣告時不進行初始化(後面將通過引用本質來解釋原因)

為什麼需要引用?

1)引用作為其它變數的別名而存在,因此在一些場合可以代替指標

2)引用相對於指標來說具有更好的可讀性和實用性

引用為java等高階的語言程式設計師提供了很大便利,其不需要了解C++中的指標,只需要按照以前的習慣來使用就可以。

引用的本質剖析(很重要!!)

1、引用其實是個常量,證明如下

int main()
{
	int a = 1;
	//int& b;   C++編譯器提示:錯誤“b”,必須初始化引用-->說明引用是個常量
	int& b = a;
}

說明: 必須初始化引用–>說明引用是個常量

2、引用其實也是個指標,證明如下

struct teacher
{
	int age;		//4個位元組
	teacher& m_techer;	
};

struct student
{
	int age;               //4個位元組
	short& weight;
};

int main()
{
	cout說明m_techer的
	                                                    引用佔4個位元組*/
	cout說明weight的引
	                                                    用佔4個位元組*/
	system("pause");
	return 0;
}

說明:從上面teacher&和short&的兩個引用中佔用的4個位元組(32位系統),可以推斷出引用其實是個指標。

根據1、2的結論可以推斷出引用其實是個指標常量或者是常量指標,下面進一步證明。

3、引用其實是個指標常量 ,證明如下

int main()
{
	int a =10;
	int m = 22;

	int& b = a;
	&b = &m;      /*疑問:  b是引用,引用是個指標,指標賦值為什麼還要在取地址符&b
	                    (因為編譯器在我們使用引用時,自動給引用披上了間接引用的外衣即:*b)
       		        編譯錯誤 “=”: 左運算元必須為左值-->引用是個指標常量,不能修改
       		          其指標的指向。*/

	system("pause");
	return 0;
}

說明:引用是個指標常量。下面會說出C++編譯器是怎麼在C語言的基礎上加入引用機制的。

4、C++編譯器在C語言的基礎上加入引用機制

說明:

1、宣告引用時,C語言將引用宣告的是指標常量。(為啥要初始化引用原因)

2、引用使用,C語言隱藏了對常指標自動間接引用,讓我們完全不用瞭解指標

3、初始化引用時,C語言隱藏了對變數的取地址符&操作,讓我們感覺是在直接給變數起別名

應用的剖析到此就結束了,下面我們來說說匿名物件吧。

什麼是匿名物件

匿名物件可以理解為是一個臨時物件,一般系統自動生成的,如你的函式返回一個物件,這個物件在返回時會生成一個臨時物件。

匿名物件的生命週期(很重要!!!)

class Cat
{
public:
    Cat()
    {
        cout<<"Cat類 無參建構函式"<<endl;
    }

    Cat(Cat& obj)
    {
        cout<<"Cat類 拷貝建構函式"<<endl;
    }

    ~Cat()
    {
        cout<<"Cat類 解構函式 "<<endl;
    }

};

void playStage() //一個舞臺,展示物件的生命週期
{
    Cat();             /*在執行此程式碼時,利用無參建構函式生成了一個匿名Cat類物件;執行完此行程式碼,
                            因為外部沒有接此匿名物件的變數,此匿名又被析構了*/
    Cat cc = Cat();    /*在執行此程式碼時,利用無參建構函式生成了一個匿名Cat類物件;然後將此匿名變
                            成了cc這個例項物件,此匿名物件沒有被析構。*/
    cout<<"cc 物件好沒有被析構"<<endl;    
}

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

輸出:

Cat類 無參建構函式
Cat類 解構函式
Cat類 無參建構函式
cc 物件好沒有被析構
Cat類 解構函式

說明:

1、在執行playStage( )函式中的Cat( )時,生成了一個匿名物件,執行完Cat( )程式碼後,此匿名物件就此消失。這就是匿名物件的生命週期。

2、在執行playStage( )函式中Cat cc = Cat();時,首先生成了一個匿名物件,因為外部有cc物件在等待被例項化,然後將此匿名物件變為了cc物件,其生命週期就變成了cc物件的生命週期。

總結:

如果生成的匿名物件在外部有物件等待被其例項化,此匿名物件的生命週期就變成了外部物件的生命週期;如果生成的匿名物件在外面沒有物件等待被其例項化,此匿名物件將會生成之後,立馬被析構。

最後希望能對大家有幫助,沙米才疏學淺,有什麼錯誤請留言指正,謝謝大家。

相關文章