1. 程式人生 > >C++引用與複製建構函式

C++引用與複製建構函式

引用

1、什麼是引用?
引用又稱別名(alias),是一種非常特殊的資料型別。它不是定義一個新的變數,而是給一個已經定義的變數重新起一個別名,也就是C++系統不為引用型別變數分配記憶體空間。引用主要用於函式之間的資料傳遞。

引用定義的格式為:
    型別 &引用變數名=已定義過的變數名;

例如:
    double number ;
    double &newnum=number ;
newnum是新定義的引用型別變數,它是變數number的別名,兩個變數代表同一塊記憶體。

2、【例4.3】使用一個函式交換兩個資料。(檢視動畫演示)
#include<iostream.h>
void swap(double & d1,double & d2) //d1和d2是引用型變數
{
       double temp ;
       temp=d1 ;
       d1=d2 ;
       d2=temp ;
}

void main(void)
{
       double x , y ;
       cout<<"請輸入x和y的值"<<'/n';
       cin>>x>>y ;
       swap(x,y) ;
       cout<<"x="<<x<<'/t'<<"y="<<y<<'/n';
}

3、引用可以作為函式的返回值
一般函式返回值時,要生成一個臨時變數作為返回值的拷貝,而用引用作為返回值時,不生成值的拷貝。

【例4.4】採用不同返回方式的求正方形面積函式的比較。
#include<iostream>
using namespace std;
double temp;
double fsqr1(double a){
    temp=a*a ; return temp;
}
double & fsqr2(double a){
    temp=a*a ; return temp;
}
int main(){
    double x=fsqr1(5.5);//第一種情況
    double y=fsqr2(5.5);//第二種情況
    cout<<"x="<<x<<'/t'<<"y="<<y<<endl;
    return 0;
}

幾點注意:

  • 對陣列只能引用陣列元素,不能引用陣列(陣列名本身為地址)。
  • 不能定義引用的引用(引用也是地址),所以當函式的引數為引用時,引用不能作實參。

複製建構函式

在建立新物件時可用同一類的另一個物件來初始化該物件,例如,得到一個和“商品甲”屬性相同的“商品乙”,當然二者的名字(物件名稱)不同。這時所用的建構函式稱為複製建構函式(Copy Constructor)。

1、什麼是複製建構函式?
對於CGoods類,可以定義複製建構函式為:
CGoods (CGoods & cgd)
{
       StrCpy (Name , cgd.Name);
       Price= cgd.price;
       Amount=cgd.Amount;
       Total_value=cgd.Total_value;
};

這裡必須注意複製建構函式的引數——同類(class)的物件採用的是引用的方式。如果把一個真實的類物件作為引數傳遞到複製建構函式,會引起無窮遞迴 。所以必須將複製建構函式的引數定義為一個類的物件的引用。

2、 若使用者沒有定義複製建構函式,系統會自動提供,稱為預設的按成員語義支援的複製建構函式,每個成員的值被依次拷貝,亦稱為預設的按成員初始化
按成員作複製是通過依次拷貝每個資料成員實現的,而不是對整個類物件按位拷貝。賦值運算子“=”稱預設的按成員拷貝賦值操作符,同類物件之間可以用“=”直接拷貝 。

3、在某些情況下,預設的按成員複製對類與物件的安全性和處理的正確性還不夠,這時就要求類的設計者提供專門的複製建構函式(Copy Constructor)和複製賦值操作符'='(Copy Assignment Operator)的定義。

4、複製建構函式的使用
例如以下:物件cary和物件carz的產生就是通過系統自動呼叫複製建構函式的,他們的屬性等和carx完全相同:
    CGoods carx(“夏利2000”,30,98000.0);
    CGoods cary=carx,carz(carx);

5、複製建構函式並不只是在同類的一個物件去初始化該類的另一個物件時使用,它還在另二個方面使用:

  • 當函式的形參是類的物件,呼叫函式時,形參與實參結合時使用。這時要在記憶體新建立一個區域性物件,並把實參拷貝到新的物件中。要呼叫拷貝建構函式;
  • 當函式的返回值是類物件時使用。理由,是要先建立一個臨時物件,再返回呼叫者。為什麼不直接用要返回的區域性物件呢?因為區域性物件在離開建立它的函式時就消亡了,所以編譯系統會在呼叫函式的表示式中建立一個臨時物件,該臨時物件的生存週期只在函式呼叫處的表示式中。所謂return X,實際上是呼叫拷貝建構函式把X拷入臨時物件。如果返回的是變數,處理過程類似,只是不呼叫建構函式。

成員物件與建構函式

◆ 1、什麼是成員物件?
【例4.6】含有成員物件的類:
class student
{
public:
       class studentID //學號類studentID的定義開始
       {
              long value;
       public:
              studentID(long id=0)
              {
                     value=id;
                     cout<<value<<endl;
              }
              ~studentID()
              {
                     cout<<"刪除"<<value<<endl;
              }
       }; //學號類studentID的定義結束,注意分號

private:
       char name[20];
       studentID id;
       //id是一個成員物件,它既是類student的成員,又是類studentID型的物件

public:
       student (char* sname=“no name”,long sid=0):id(sid)
       //關注id的構造!
       //sname 現暫看作字串,char*是指向字元的指標型別
       {
              cout<<“學生名:”<<sname<<endl;
              strcpy(name,sname);
       }

}; //類student定義結束

◆ 2、student型的物件構造時,其中的成員物件id如何產生?
上面程式碼中,student類的建構函式頭後半部分語句 :id(sid) 即可使系統呼叫物件id所屬類studentID的建構函式,以產生id。

3、C++中對含成員物件的類物件的建構函式有特殊的格式:
    類名::建構函式名(引數總表):成員物件1(引數表1),成員物件2(引數表2),……成員物件n(引數表n)
    {……}

4、先呼叫哪個物件成員的建構函式,取決與它們在類中說明的順序;物件產生時,先初始化物件成員,後初始化其他成員;物件撤銷時,相反。