[C++_G_CLASS] C++中類的建構函式__Jquery

來源:互聯網
上載者:User
首先看一個題目:
有一個類
class A
{
public:
    A();                                    //c1
    A(const A&);                      //c2
    A(int i);                               //c3
    A& operator=(const A&);   //c4
};
問如下語句都調用哪些建構函式。

A a;           //s1
A b=a;      //s2
b=a;         //s3
A c();        //s4
A b(a);      //s5
A()=5;      //s6

先講一下收穫:

   1 一個類一般要提供3個建構函式,預設建構函式; 拷貝建構函式; 賦值函數(operator=重載)。
      如果不定義這3個函數,編譯器也會產生預設的預設建構函式; 拷貝建構函式。( 賦值函數不太確定是否會產生預設的)。

   2 拷貝建構函式和賦值函數,預設情況下,實行位拷貝。
      類中可能含有指向某記憶體空間的指標,是定義這兩個函數的主要原因。你需要決定是否要求指標指向同一空間,或者再次分配記憶體。

   3 使用預設建構函式時,必須不能使用括弧。
   例如s1, s4。s1顯然是調用c1。s4呢。s4是聲明了一個傳回值為A的函數。

   4 拷貝建構函式和賦值函數的區別,拷貝建構函式在建立對象的時候使用; 而賦值函數在賦值時引用(廢話:))
    例如s2是調用c2。s3是調用c4。如果他們中任何一個沒定義,那麼相應的調用就會使用位拷貝.
    可能s2中的文法令人和s3混淆,s5中的文法就相當清晰了。

   5 如果類中定義了包含某類型T的參數的建構函式,則就有了T到類的類型轉換。
   例如s6。5是int型的,類A有這樣的參數的建構函式,那麼先將5利用相應的建構函式( A(int) )轉化為A的對象,或者說是產生一個A的對象。等號左邊,顯然是調用預設建構函式產生一個類的對象。最後調用賦值函數,完成賦值。

   6 還得談一下編譯器的區別。
    A b()
   {
      A a;
      return a;
    }

    A c=b();

   在G++下,上面的代碼是不調用拷貝建構函式或預設建構函式的。
   而使用VC下,是調用拷貝建構函式的。
   我個人也是認為應該調用拷貝建構函式,首先是由局部變數產生返回的臨時變數,其次是由傳回值構造新的對象。需要調用兩次。但這裡編譯器G++做了最佳化。
    如果在拷貝函數中改變了某個成員變數i的值,那麼上面的代碼是不會成功的。
    比如i預設構造為0, 拷貝建構函式把它修改為2, 然後經過上面的代碼,在g++下c.i仍然是0而不是2。



實驗代碼如下:
平台
g++ version 4.0.3
Ubuntu 6.06 LTS - the Dapper Drake - released in June 2006

#include <cstdio>
//using namespace std;

/*
    拷貝建構函式和=號重載的作用在於
    防止位拷貝對類中指標,既而記憶體使用量的影響
    解構函式要合理的釋放記憶體

    =號重載在VC中是要求必須有傳回值的。
    =號重載記得要判斷是否是自賦值。
    =號重載最好是返回A&。這樣就提高了效率。
  */
class A
{
    //除const static的變數可以在類體內賦值外,其餘變數均不可以賦值
    int i;

public:

    //預設建構函式
    A()
    {
        i=0;
        printf("A/n");
    }

    //拷貝建構函式
    //拷貝建構函式的作用主要在於:如果類中含有指標,可以決定
    //                該指標是否需要指向新的記憶體空間
    //                否則,位拷貝的話只是完成簡單的複製。
    A(const A&)
    {
        i=1;
        printf("AConst/n");
    }
   
    //一般建構函式
    A(int i)
    {
        i=2;
        printf("AInt/n");
    }

    //=號重載
    //傳回值如果是A,則如果有return語句,則會調用拷貝建構函式
    //         A& 則不會
     A& operator=(const A&)
    {
        i=3;
        printf("A=/n");
        //
        return *this;
        /*
        A a;
        //此時也不調用拷貝建構函式, 編譯器最佳化了。
        //答案應該是肯定的。VC編譯器中沒有對此作最佳化,仍然需要調用
        return a;
        */
    }

    void speak()
    {
        printf("i = %d/n",i);
    }

    static void CSpeak()
    {
        printf("I'm the class!/n");
    }
};

int main (int argc, char * argv[])
{
    printf("Test 1: /n");
    A a;
    a.speak();
    printf("/n");
   
    printf("Test 2: /n");
    //先調用A(int),利用參數5構造一個A對象
         //                            或說成將5強制類型轉換為A
    //然後調用預設建構函式構造一個A對象
    //再然後利用重載運算子賦值
    A()=5;
    printf("/n");

    printf("Test 3: /n");
    //不是聲明對象,而是聲明函數
    A b();
   
    b().speak();;
    printf("/n");

    printf("Test 4: /n");
    A * c=new A();
    printf("/n");

    printf("Test 5: /n");
    A d;
    A e;
    d=e;//如果不重載運算子,不會調用拷貝建構函式
    d.speak();
    e.speak();
    printf("/n");
   
    printf("Test 6: /n");
    A f;
    A g=f;//此時調用拷貝建構函式
    printf("/n");


    return 1;
}


A b()
{
    /*
    A a;
    a.speak();
    //不調用拷貝建構函式,VC編譯器中沒有對此作最佳化,仍然需要調用
    return a;
    */

    //調用拷貝建構函式
    return (*(new A()));
}
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.