C++拷貝建構函式與運算子多載

來源:互聯網
上載者:User

拷貝建構函式與運算子的重載 

* 多態 

  - 前堤:繼承,虛函數,指標或引用 

  - 類型轉換 : dynamic_cast 把父類*轉換成子類* 

  - 純虛函數 : 保證此函數一定不會被執行,抽象類別,不能建立對象. 

 

* 友元 

  - 內部授權,不是成員,這一點很重要,因此也沒有this,與之相關的一切 

 

也沒有. 

  - 打破封裝,必須有一個類的內部聲明,可訪問任何成員通過 對象.來訪 

 

問. 

 

* 靜態 

  - 是成員 

  - 大家共用一份成員,整個類共用的成員. 

- 待用資料成員: 在外部初始化 

- 靜態函數只能訪問靜態成員,類名::成員 

==================================================== 

* 運算子多載(c++特有功能) 

* 內部類 

* 異常 

 

拷貝建構函式除了名字特殊外毫無特殊之處.如下 

C++代碼 

A(const A& obj){  

    cout << "我是拷貝建構函式" << endl;  

}  

A a = obj// 與 A a(obj)是等價的  

 

 

C++代碼 

#include <iostream>  

using namespace std;  

 

class A {  

        int data;  

public :  

        A():data(5){ //初始化列表初始化的是成員而不是形參  

                cout << "A()" << endl;  

        }  

        A(int d):data(d){  

                cout << "A(int)" << endl;  

        }  

        A(bool b):data(b?123:234){  

                cout << "A(bool)" << endl;  

        }  

        A(char c) : data((int)c){  

                cout << "A(char)" << endl;  

        }  

        A(const A& o) : data(o.data){  

                cout << "A(const A&)" << endl;  

        }  

        void show(){  

                cout << "data=" << data << endl;  

        }  

        virtual ~A(){  

                cout << "~A()" << endl;  

        }  

};  

int main()  

{  

        A a1;//調用無參建構函式  

        A a2(28);  

        A a3(true);  

        A a4('S');  

        A a5(a2);  

}  

 

//用引用的好處  

#include <iostream>  

using namespace std;  

 

class A {  

        int data;  

public :  

        A():data(5){ //初始化列表初始化的是成員而不是形參  

                cout << "A()" << endl;  

        }  

        A(int d):data(d){  

                cout << "A(int)" << endl;  

        }  

        A(bool b):data(b?123:234){  

                cout << "A(bool)" << endl;  

        }  

        A(char c) : data((int)c){  

                cout << "A(char)" << endl;  

        }  

        //A(const A& o) : data(o.data){  

        //       cout << "A(const A&)" << endl;  

        //}  

    //形參是一個新變數,在調用時建立,由實參來初始化.  

    A(A o) : data(o.data){  //這樣寫是錯誤的,進入死迴圈  

                cout << "A(const A&)" << endl;  

        }  

//建立對象時要調建構函式,調建構函式建立形參,形參又是一個新對象,  

//建立新對象又要調建構函式,調建構函式又要建立形參,.......  

        void show() const{  

                cout << "data=" << data << endl;  

        }  

        virtual ~A(){  

                cout << "~A()" << endl;  

        //      show(200);  

//      show(false);  

//      show('A');  

        //A a2(28);  

        //A a3(true);  

        //A a4('S');  

        //A a5(a2);  

        }  

};  

void show( A obj)  

{  

        obj.show();  

}  

void func( const A& obj)  

{  

        obj.show();  

}  

int main()  

{  

        A a1;//調用無參建構函式  

        show(a1);  

        func(a1);  

}  

 

 

 

當類無建構函式時,會自動產生A(),A(const A&)建構函式. 

 

+ 當類成員有指標成員指向動態記憶體時預設拷貝建構函式會出問題. 

   因為它會使兩個指標指向同一個地方導致混亂. 

   這時我們需要重寫這個拷貝建構函式.如下樣本: 

C++代碼 

#include <iostream>  

using namespace std;  

 

class A {  

        int data;  

public :  

        A():data(5){ //初始化列表初始化的是成員而不是形參  

                cout << "A()" << endl;  

        }  

    //拷貝建構函式  

        A(const A& o)/* :data(o.data) */ {  

                cout << "A(const A&)" << endl;  

        }  

        void show(){  

                cout << "data=" << data << endl;  

        }  

        virtual ~A(){  

                cout << "~A()" << endl;  

        }  

};  

int main()  

{  

        A a1;  

    a1.show(); //輸出正常  

    A a2(a1);  

    a2.show(); //輸出垃圾資料,所以初始化不能少  

}    

 

在類的成員函數中可以訪問本類中任何成員變數. 

 

自已定義拷貝建構函式之後,就沒有預設的拷貝建構函式了,要在 

 

自己定義的拷貝建構函式中處理所有需要處理的資料.                  

 

 

C++代碼 

//動態數組類,長度可動態變化.未完整版  

#include <iostream>  

using namespace std;  

 

class Array {  

        char * p;  

        int len;  

public :  

        Array(int n ) : len(n),p(NULL){  

                resize(n);  

        }  

        Array( const Array& o ) : len(o.len) {  

                p = new char[len];  

                for( int i=0; i<len; i++ )  

                        p[i] = o.p[i];  

        }  

        void resize( int n ){  

                char * q = new char[n];  

                int min = (n<len?n:len);  

                if(p!=NULL){  

                        for( int i=0; i<min; i++)  

                                q[i] = p[i];  

                        delete[] p;  

                }  

                p = q;  

                for( int i=min; i<n; i++)  

                        p[i] = '/0';  

                len = n;  

        }  

        int size(){  

                return len;  

        }  

        void set( int index, char c ){  

                if( index<0 || index>len ){  

                        cout << "Error" << endl;  

                        return;  

                }  

                p[index] = c;  

        }  

        char get( int index ){  

                if( index<0 || index>len ){  

                        cout << "Error" << endl;  

                        return '^';  

                }  

                return p[index];  

        }  

        void fill ( char start, int skip ){  

                for( int i=0; i<len; i++)  

                        p[i] = start + i*skip;  

        }  

        void show(){  

                for( int i=0; i<len; i++){  

                        cout << p[i];  

                }  

        }  

        ~Array(){  

                if(p!=NULL){  

                        delete[ ] p;  

                        p = NULL;  

                }  

        }  

};  //end class Array   

 

int main()  

{  

        Array a1(10);  

        a1.fill('a',2);  

        a1.show();  

        cout << endl;  

        Array a2(a1);  

        a2.fill('A',2);  

        a2.show();  

        cout << endl;  

        a1.show();  

        cout << endl;  

        cout << "------------------" << endl;  

        cout << "Please input text(end by '$') : " << endl;  

        for(int i=0;;i++){  

                char c;  

                cin >> c;  

                if(c=='$')  

                        break;  

                else if(i+1>a1.size()){  

                        a1.resize(a1.size()+10);  

                }  

                        a1.set(i,c);  

        }  

        a1.show();  

        cout << endl;  

        for( int i=0; i<a1.size(); i++){  

                cout << a1.get(i);  

        }  

}  

 

======================================== 

 

預設的拷貝建構函式是淺拷貝,自己寫的拷貝建構函式是深拷貝. 

 

* 運算子函數 

* 單目運算子 

 

C++代碼 

A operator+(A obj1,Aobj2){/* code */};  

 

A a1(30),a2(50);  

A result;  

result = a1 + a2; //會去調A operator+(A obj1,Aobj2)  

result.show();  

 

C++代碼 

//樣本  

//由程式可知成員比友員要方便,少傳一個參數  

#include <iostream>  

using namespace std;  

class A{  

    //code  

    A sub( const A& o){  

        return A(data-o.data);  

    }  

    A oprator-()/......  

};  

A operator-(const A& o1, const A& o2){  

 

    //code...  

}  

int main()  

{  

    A obj1(40),obj2(50);  

    A obj3,obj4;  

    obj3 = obj1.sub(obj2);  

    obj3.show();  

    obj4 = obj1 - obj2; //會去調obj1.aperator-(..)  

}  

 

 

運算子多載就是自已寫運算子函數來規定運算子如何工作. 

 

-------------------------- 

運算子函數的實現方法: 

* 友元運算子函數: 

  - 在類中聲明friend 

  - 定義:傳回型別 operatorX(形參1,形參2) 

  - 調用: obj1 X obj2 解釋成 operatorX(obj1,obj2),傳回值作為運 

 

算結果 

* 成員函數: 直接在類中定義 

  - 定義: 傳回型別 operatorX(形參1) 

  - 調用: obj1 X obj2 解釋成 obj1.operator(obj2),傳回值作為運算 

 

結果 

 

cout << f1 << f2;//用重載運算子表示,只能通過友員來實現 

// 如果要用成員函數,則會有cout.operator<<(const F& f),所以這是不 

 

// 可能的.因此只能用友員來實現,operator<<(cout,f) 

// 而cout是ostream型的,因此有以下標準格式.注意不能加const,因為// 

 

cout是要改變的,會改變裡的緩衝成員. 

ostream& operator<<( /* 不能加const */ ostream& cout, const 

 

F&)  //輸出運算子的標準重載格式. 

friend istream& operator>>(istream& is, F& f){ 

 

}//輸入運算子多載標準格式 

 

C++代碼 

//重載運算子完整例子  

//雙目運算子多載  

#include <iostream>  

using namespace std;  

class F{  

        int n;  

        int d;  

public :  

        F(int n=0, int d=1):n(n),d(d){}  

        friend ostream& operator<<(ostream& os, const F& f){  

                os << '[' <<  f.n << '/' << f.d <<']';  

                return os;  

        }  

        F operator*(const F& o) {  

                return F(n*o.n,d*o.d);  

        }  

        friend F operator/(const F& f1,const F& f2){  

                return F(f1.n*f2.d,f1.d*f2.n);  

        }  

        friend istream& operator>>(istream& is, F& f){  

                char ch;  

                is >> f.n >> ch >> f.d;  

                return is;  

        }  

};  

 

int main()  

{  

        F f1(3,5),f2(11,7),f;  

        cout << f1 << '*' << f2 << '=' << f1*f2 << endl;  

        cout << f1 << '/' << f2 << '=' << f1/f2 << endl;  

        cout << "Input 2 fractions :";  

        cin >> f1 >> f2;  

        cout <<"f1=" << f1 << endl;  

        cout << "f2=" << f2 << endl;  

}  

 

 

* 單目運算子多載 

  -友元函數形式,傳回型別 operatorX(形參) 

使用:X obj ---> operatorX(obj); 

  -成員函數形式 盡量用成員  傳回型別 operatorX(/*無形參*/) 

使用: X obj ---> obj.operator(); 

 

c++代碼 

//單目運算子多載  

//把後++,後--當作雙目運算子,第二個運算元是整形.  

#include <iostream>  

using namespace std;  

 

class A{  

        int data;  

public :  

        A(int d=0):data(d){}  

        friend ostream& operator<<(ostream& os,const A& a){  

        os << a.data;  

        return os;  

        }  

        friend istream& operator>>(istream& is,A& a){  

        is >> a.data;  

        return is;  

        }  

        friend A& operator++(A& a){  

                a.data += 10;  

                return a;  

        }  

        A& operator--(){  

                data -= 10;  

                return *this;  

        }  

    //後加加,規定一個整形為形參,與先加加區分  

        friend A/* 此時不再用引用 */ operator++(A& a,int){  

                A old(a);  

                a.data += 1;  

                return old;  

        }  

    //後減減,規定為一個整形為形參,與先減減區分.  

        A /*不要引用*/ operator--(int){  

                A old(*this);  

                data -= 1;  

                return old;  

        }  

};  

 

int main()  

{  

        A a1(50),a2(100);  

        cout << "a1=" <<a1 << endl;  

        cout << "a2=" <<a2 << endl;  

        cout << "++a1=" << ++a1 << endl;  

        cout << "--a1=" << --a1 << endl;  

        cout << "a1++=" << a1++ << endl;  

        cout << "a1=" <<a1 << endl;  

        cout << "a2--=" << a2-- << endl;  

        cout << "a2=" <<a2 << endl;  

 

}  

 

 

   運算子多載提供了一個自己規定運算子式作方式的方法,至少有一個操 

 

作數是自訂類型的.基本類型我們是規定不了的. 

   強制類型轉換:類型(資料) --> (不必寫傳回型別,因為始終與後面的類 

 

型是相同的) operator類型(無形參) 只能寫成成員函數,不能是友員. 

 

C++代碼 

#include<iostream>  

using namespace std;  

 

class A{  

    int data;  

public:  

    A(int d=0):data(d){}  

    operator int(){  

        return data;  

    }  

    operator bool(){  

        return data!=0;  

    }  

    operator char(){  

        return (char)data;  

    }  

};  

int main()  

{  

    A a1(65),a2(200);  

    cout << "a1=" << (char)a1 << endl;  

    int d=a2;  

    if(a2)  

        cout << "good" << endl;  

}  

 

對自訂類型的對象,使用運算子時,總是調用相應的運算子函數 

 

三目運算子不能重載. 

等號是雙目運算子也可重載,它也只能是成員. 

還有點號('.')不能重載. 

雙冒號(::)不能重載. 

sizeof(類型)沒法重載. 

#號不是運算子,無所謂重載. 

'= () [] -> 類型轉換'只能是成員函數來重載,其它的隨便,我們建議盡量 

 

使用成員函數來寫,有點只能用友元,比如輸入輸出. 

================================================== 

+ 雙目運算子多載 

  - 友元形式:返  operator符號(形1,形2) 

  - 成員形式:返 operator符號(形) 

+ 單目運算子多載 

  - 友元: 返  operator符號(形參) 

  - 成員: 返 operator符號() 

+ 特例 

  - 加加 

- 先加加 

- 後加加 返回 operator符號(形,int) 

  - 減減 

- 先減減 

- 後減減 

  - 類型轉換 只能是成員perator 空格 類型();

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.