c++ mooc 構造函數,複製構造函數,類型轉換構造函數, 析構函數

構造函數:

是在對象已經具有空間以後做一些初始化的工作,不負責分配空間

是成員函數的一種,與類名相同,可以帶參,無返回值,對對象做初始化

類默認有構造函數,無參無操作

有對象生成時一定調用構造函數

一個類可有多個構造函數

class Rectangle:
{
    private: 
        int w,h;
    public:
        Rectangle(int i, int j=0);
        Rectangle();
        Rectangle(Rectangle r1, Rectangle r2);
};

//三個構造函數
Rectangle::Rectangle(int i, int j=0){
        w = i;
        h = j;
}
Rectangle::Rectangle(){
        w = 0;
        h = 0;
}
Rectangle::Rectangle(Rectangle r1, Rectangle r2){
        w = r1.w + r2.w;
        h = r1.h + r2.h;
}


int main(){
    //第二個,第一個,第三個構造函數
    Rectangle r(),r1(1),r2(r,r1);
    //Rectangle r;  也用第二個
}

 

構造函數在數組的使用

 

指針不會引發對象的生成:

Rectangle *r[3];  //不會調用任何構造函數,因爲是一個指針數組
Rectangle *r[3]={new Rectangle(4), NULL, new Rectangle(1,2)} //只生成兩個對象,new返回爲指針

 

複製構造函數

形如  X::X( X& x) 或 X::X(const X& x) ,參數爲同類對象的引用,無定義編譯器默認生成,完成兩個對象複製的功能

複製構造函數與無參構造函數區別:

      1. 無參構造函數也稱默認構造函數,不一定存在(你不寫任何構造函數編譯器纔會默認生成)

      2. 複製構造函數一定存在(要麼你寫要麼編譯器幫你寫),複製構造函數只有一個

class Complex:{
    private:
        double img,re;
};

int main(){
Complex c1;
Complex c2(c1);  //調用缺省的默認的複製構造函數,c2與c1一樣
}

複製構造函數起作用的三種情況:

//1.
Complex c1;

//2.初始化同類的另一個對象
Complex c2(c1);   //或Complex c2=c1;

//某函數Func()的參數是類A的對象,則Func調用時,類A的複製構造函數將被調用
class A:
{    
    public:
        A(){};
        A(A & a){cout<<"copy construct"<<endl};
};

void Func(A a1){}

int main(){
    A a2;
    Func(a2);     //此時a1對象的初始化調用複製構造函數,但我們的複製構造函數不是拷貝,所以a1可
                  //能不是a2的拷貝  
    return 0;
}

//3.若函數Func的返回值爲A的對象時,Func返回時A的複製構造函數被調用
class A:
{    
    public:
        int v;
        A(int n){v=n;};
        A(const A & a){
        v = a.v
        cout<<"copy construct"<<endl
        };
};
A Func(){
    A a1(3);
    return a1;
}
int main(){
    cout<<Func().v<<endl;  //3
    
    return 0;
}

對象間的賦值不等於複製構造函數被調用比如:

Complex c1;
c1=c2;

 

爲了減少函數調用時,複製構造函數調用所產生的時間開銷,可以用常量引用參數

void Func(const A & a ){}

引用的參數與實參是一回事,不會生成對象,若想讓函數內部操作改變形參不改變實參,加上const

 

 

類型轉換構造函數

爲了實現類型轉換

只有一個參數且不是複製構造函數

需要時編譯器自動調用,生成一個無名臨時對象

class Complex:
{
    public:
        double a,b;
        Complex(double i, double j){a=i;b=j;}
        Complex(int i){a=i; b=0;}  //double to int
};

int main(){
    Complex c1(7,8);  //7.0,8.0
    Complex c2=12;    //a=12,b=0
    c1=9;             //編譯器將9自動轉換爲一個無名臨時對象其a=9,b=0,再將這個臨時對象賦給c1
    return 0;
}

 

析構函數(destructor)

在對象消亡時被調用(可爲釋放空間等),一個類最多一個

若不寫編譯器會自動生成(什麼都不做)

函數名爲:‘~’ + ‘className’

無參無返回值

在對象的空間被回收前的操作

class String:
{
       private:
            char *p;
       public:
            String(){
                p = new char[10];
            }
            ~ String();
};

String::~ String(){
    delete []p;
}

對象數組生命週期結束時,其中的每個元素的析構函數都會被調用

消亡的幾種情況:

//1. main函數結束時
class A:
{
    public:
        int a;
    ~ A(){cout<< "destructor" <<endl;}        
};

int main(){
A a[2];
cout<< "end main" <<endl;

return 0;
}
//輸出結果爲:
//end main
//destructor
//destructor


//2.new出的對象,delete時消亡,不delete不消亡
A *a;
a = new A;
delete a;   //析構函數調用

A a1[3];
delete [] a;  //析構函數調用三次


//3. 對象作爲函數返回值,返回後調用析構函數
class A:
{
    public:
        int a;
    ~ A(){cout<< "destructor" <<endl;}        
};

A func(A sa)              //調用默認複製構造函數初始化形參sa
{
    return sa;            //返回形參sa後析構函數被調用
}

int main(){
    A a;
    a = func(a);          //func(a)生成一個返回值對象(臨時對象),用複製構造函數初始化,其值賦
                          //值給a,執行完這條語句後,臨時對象消亡,調用析構函數
    cout<< "end main" <<endl; 

    return 0;             //main結束後,全局對象a消亡,調用析構函數
}
//輸出結果爲:
//destructor
//destructor
//end main
//destructor

 

相關實例

析構函數和構造函數被調用實例:

class A:
{
    public:
        int a;
        A(int i){     //構造函數,也可算類型轉換構造函數
            a=i;
            cout << "a" << a << " construct" << endl;
        };
        ~ A(){
            cout << "a"<< a << " destruct" << endl;
        }        
};

A a1(1);                               //step1:全局對象在main之前初始化,在整個程序結束後消亡

void func(){                           
    static A a2(2);                    //step8:靜態局部變量初始化,在全部程序結束後消亡
    A a3(3);                           //step9:局部變量a3初始化,在func結束後消亡
    cout << "func end" << endl;
}

int main(){                   
    A a4(4);                           //step2:初始化a4,在main結束後消亡
    a4 = 6;                            //step3:類型轉換構造函數生成值爲6的臨時對象
                                       //step4:臨時對象賦值語句結束後消亡
    cout << "main" << endl;            //step5
    {A a5(5);}                         //step6:局部對象a5生成
                                       //step7:包含a5的最內層大括號結束後a5消亡
    func();
    cout << "end main" << endl;
}

//輸出結果
// a1 construct
// a2 construct
// a4 construct
// a6 construct
// a6 destruct
// main
// a5 construct
// a5 destruct
// a2 construct
// a3 construct
// func end
// a3 destruct
// end main
// a6 destruct       //先消亡main內的
// a2 destruct       //因爲a1比a2先初始化,後消亡
// a1 destruct

構造函數在不同編譯器中表現

dev c++呼籲優化目的沒有生成返回值臨時對象,一般情況下沒什麼問題

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章