構(gòu)造函數(shù)
引入
在c++的類中,構(gòu)造函數(shù)是一種特殊的成員函數(shù),在每次創(chuàng)建創(chuàng)建一個(gè)類的時(shí)候會(huì)默認(rèn)調(diào)用構(gòu)造函數(shù)進(jìn)行初始化工作。
構(gòu)造函數(shù)用來完成一些必要的初始化工作,有了構(gòu)造函數(shù)之后,就無需再單獨(dú)寫初始化函數(shù),并且也不必?fù)?dān)心忘記調(diào)用初始化函數(shù)。
基本概念
構(gòu)造函數(shù)具有如下幾個(gè)特點(diǎn)
- 名字與類名相同,可以有參數(shù),但是不能有返回值(void也不行)
- 作用是對(duì)對(duì)象進(jìn)行初始化工作,如給成員變量賦值等。
- 如果定義類時(shí)沒有寫構(gòu)造函數(shù),系統(tǒng)會(huì)生成一個(gè)默認(rèn)的無參構(gòu)造函數(shù),默認(rèn)構(gòu)造函數(shù)沒有參數(shù),不做任何工作。
- 如果定義了構(gòu)造函數(shù),系統(tǒng)不再生成默認(rèn)的無參構(gòu)造函數(shù)
- 對(duì)象生成時(shí)構(gòu)造函數(shù)自動(dòng)調(diào)用,對(duì)象一旦生成,不能在其上再次執(zhí)行構(gòu)造函數(shù)
- 一個(gè)類可以有多個(gè)構(gòu)造函數(shù),為重載關(guān)系
構(gòu)造函數(shù)
默認(rèn)無參構(gòu)造函數(shù)
下面來看一個(gè)簡單的例子。
class Complex {//復(fù)數(shù)類
private:
double real, imag;//分別表示實(shí)部以及虛部
public:
void set(double r, double i) {
real = r;
imag = i;
}
};
對(duì)于上面的復(fù)數(shù)類,real表示實(shí)部,imag表示虛部,set(set(double r, double i))函數(shù)為初始化函數(shù),我們并沒有為其編寫構(gòu)造函數(shù),此時(shí)編譯系統(tǒng)將生成一個(gè)默認(rèn)的無參構(gòu)造函數(shù)。
假設(shè)有如下調(diào)用:
int main() {
Complex c1;//默認(rèn)構(gòu)造函數(shù)被調(diào)用
Complex* c2 = new Complex;//默認(rèn)構(gòu)造函數(shù)被調(diào)用
return 0;
}
在對(duì)象生成的時(shí)候,編譯系統(tǒng)自動(dòng)調(diào)用默認(rèn)的無參構(gòu)造函數(shù)對(duì)其進(jìn)行初始化工作(什么都沒做),此時(shí)我們必須自己調(diào)用set(double r, double i)函數(shù)才能對(duì)其進(jìn)行初始化操作。
編寫構(gòu)造函數(shù)
接下來我們?yōu)樯厦娴念惥帉懸粋€(gè)構(gòu)造函數(shù)
class Complex {//復(fù)數(shù)類
private:
double real, imag;//分別表示實(shí)部以及虛部
public:
Complex(double r, double i = 0) {
real = r;
imag = i;
}
};
int main() {
Complex c1;//錯(cuò)誤,參數(shù)不匹配
Complex* c2 = new Complex;//錯(cuò)誤,參數(shù)不匹配
return 0;
}
當(dāng)我們?cè)谡{(diào)用上面的代碼生成對(duì)象c1、c2時(shí),編譯系統(tǒng)會(huì)給我們報(bào)錯(cuò)。原因是我們編寫的構(gòu)造函數(shù)需要接收至少一個(gè)參數(shù),而我們?cè)诔跏蓟臅r(shí)候沒有給出任何的參數(shù)。
對(duì)上面的代碼進(jìn)行如下的改動(dòng):
int main() {
Complex c1(1);//OK
Complex* c2 = new Complex(2,5);//OK
return 0;
}
此時(shí)c1、c2就可以正常地生成。
- 對(duì)于
c1對(duì)象,用1來初始化實(shí)部,用缺省的0初始化虛部。 - 對(duì)于
c2對(duì)象,用2來初始化實(shí)部,用5初始化虛部。
構(gòu)造函數(shù)重載
對(duì)于同一個(gè)類,可以有多個(gè)構(gòu)造函數(shù),只要參數(shù)個(gè)數(shù)或類型不同就可,他們之間為重載的關(guān)系。
class Complex {//復(fù)數(shù)類
private:
double real, imag;//分別表示實(shí)部以及虛部
public:
//構(gòu)造函數(shù)
Complex();
Complex(double r);
Complex(double r, double i);
Complex(Complex c1, Complex c2);
};
Complex::Complex() {
real = 0;
imag = 0;
}
Complex::Complex(double r) {
real = r;
imag = 0;
}
Complex::Complex(double r, double i) {
real = r;
imag = i;
}
Complex::Complex(Complex c1, Complex c2) {
real = c1.real + c2.real;
imag = c1.imag + c2.imag;
}
在上面的類中,分別寫了四個(gè)構(gòu)造函數(shù)
-
Complex()無參構(gòu)造函數(shù),real和imag都初始化為0 -
Complex(double r)將real初始化為r,imag初始化為0 -
Complex(double r, double i)將real初始化為r,imag初始化為i -
Complex(Complex c1, Complex c2)將real初始化為c1.real + c2.real,imag初始化為c1.imag + c2.imag
對(duì)于上面的類,假設(shè)我們有如下調(diào)用:
int main() {
Complex c1;//調(diào)用Complex()構(gòu)造函數(shù)
Complex c2(2);//調(diào)用Complex(double r)構(gòu)造函數(shù)
Complex c3(2, 3);//調(diào)用Complex(double r, double i)構(gòu)造函數(shù)
Complex c4(c1, c2);//Complex(Complex c1, Complex c2)構(gòu)造函數(shù)
return 0;
}
- 對(duì)于
c1對(duì)象,調(diào)用Complex()無參構(gòu)造函數(shù),將real和imag都初始化為0 - 對(duì)于
c2對(duì)象,調(diào)用Complex(double r)構(gòu)造函數(shù),將real初始化為2,imag初始化為0 - 對(duì)于
c3對(duì)象,調(diào)用Complex(double r, double i)構(gòu)造函數(shù),將real初始化為2,imag初始化為3 - 對(duì)于
c4對(duì)象,調(diào)用Complex(Complex c1, Complex c2)將real初始化為c1.real + c2.real=2,imag初始化為c1.imag + c2.imag=0
構(gòu)造函數(shù)在數(shù)組中的使用
下面我們通過一個(gè)實(shí)例來查看對(duì)與對(duì)象數(shù)組是如何調(diào)用構(gòu)造函數(shù)進(jìn)行初始化的。
class Complex {//復(fù)數(shù)類
private:
double real, imag;//分別表示實(shí)部以及虛部
public:
//構(gòu)造函數(shù)
Complex() {
cout << "無參構(gòu)造函數(shù)初始化" << endl;
}
Complex(double r) {
cout << "一個(gè)參數(shù)的構(gòu)造函數(shù)初始化" << endl;
}
Complex(double r, double i) {
cout << "兩個(gè)參數(shù)的構(gòu)造函數(shù)初始化" << endl;
}
};
我們?yōu)樯厦娴念悓懥巳齻€(gè)構(gòu)造函數(shù),在調(diào)用無參構(gòu)造函數(shù)時(shí)輸出無參構(gòu)造函數(shù)初始化,調(diào)用一個(gè)參數(shù)的構(gòu)造函數(shù)時(shí)輸出一個(gè)參數(shù)的構(gòu)造函數(shù)初始化,調(diào)用兩個(gè)構(gòu)造函數(shù)初始化時(shí)輸出兩個(gè)參數(shù)的構(gòu)造函數(shù)初始化。
假設(shè)我們有如下的對(duì)象生成:
int main() {
cout << "array1" << endl;
Complex array1[3];
cout << "array2" << endl;
Complex array2[3] = { 1,2 };
cout << "array3" << endl;
Complex array3[3] = { 1,Complex(1,2) };
cout << "array4" << endl;
Complex* array4 = new Complex[3];
cout << "array5" << endl;
Complex* array5[3] = { new Complex(1),new Complex(2,3) };
delete[]array4;
return 0;
}
- 對(duì)于
array1生成的三個(gè)對(duì)象,我們沒有為其指定參數(shù),所以都調(diào)用無參構(gòu)造函數(shù)進(jìn)行初始化。 - 對(duì)于
array2生成的三個(gè)對(duì)象,我們指定了前兩個(gè)的參數(shù)表為1和2,所以調(diào)用一個(gè)參數(shù)的構(gòu)造函數(shù)進(jìn)行初始化,第三個(gè)對(duì)象沒有指定參數(shù),所以調(diào)用無參構(gòu)造函數(shù)進(jìn)行初始。 - 對(duì)于
array3生成的三個(gè)對(duì)象,第一個(gè)對(duì)象參數(shù)為1,所以調(diào)用無參構(gòu)造函數(shù)初始化,第二個(gè)對(duì)象參數(shù)為(1,2),所以調(diào)用兩個(gè)參數(shù)的構(gòu)造函數(shù)初始化,對(duì)于第三個(gè)對(duì)象,我們沒有指定參數(shù),所以調(diào)用無參構(gòu)造函數(shù)初始化。 -
array4為一個(gè)Complex類的指針,通過new運(yùn)算符動(dòng)態(tài)分配三個(gè)對(duì)象,并將其首地址返回給array4,在此我們并沒有為new出來的三個(gè)對(duì)象指定初始化參數(shù),所以三個(gè)對(duì)象都調(diào)用無參構(gòu)造函數(shù)初始化。 -
array5為一個(gè)Complex類的指針數(shù)組,包含三個(gè)指針對(duì)象。第一個(gè)new Complex(1)生成了一個(gè)對(duì)象,且參數(shù)為1,所以調(diào)用一個(gè)參數(shù)的構(gòu)造函數(shù);第二個(gè)元素通過new Complex(2,3)生成一個(gè)對(duì)象,且參數(shù)為(2,3),所以調(diào)用兩個(gè)參數(shù)的構(gòu)造函數(shù);第三個(gè)我們沒有為其動(dòng)態(tài)分配內(nèi)存空間,所以不會(huì)導(dǎo)致對(duì)象的生成,僅存在一個(gè)對(duì)象指針。所以array5僅生成了兩個(gè)對(duì)象。
對(duì)于上面的程序,我們可以得到如下的運(yùn)行結(jié)果:
array1
無參構(gòu)造函數(shù)初始化
無參構(gòu)造函數(shù)初始化
無參構(gòu)造函數(shù)初始化
array2
一個(gè)參數(shù)的構(gòu)造函數(shù)初始化
一個(gè)參數(shù)的構(gòu)造函數(shù)初始化
無參構(gòu)造函數(shù)初始化
array3
一個(gè)參數(shù)的構(gòu)造函數(shù)初始化
兩個(gè)參數(shù)的構(gòu)造函數(shù)初始化
無參構(gòu)造函數(shù)初始化
array4
無參構(gòu)造函數(shù)初始化
無參構(gòu)造函數(shù)初始化
無參構(gòu)造函數(shù)初始化
array5
一個(gè)參數(shù)的構(gòu)造函數(shù)初始化
兩個(gè)參數(shù)的構(gòu)造函數(shù)初始化