天天看點

C/C++學習之路(一)

         今天我想要寫的是關于調用構造函數的問題。

         首先,我們先來弄懂關于構造函數的定義。在百度百科上,是這麼定義的:構造函數 ,是一種特殊的方法。主要用來在建立對象時初始化對象, 即為對象成員變量賦初始值,總與new運算符一起使用在建立對象的語句中。特别的一個類可以有多個構造函數 ,可根據其參數個數的不同或參數類型的不同來區分它們 即構造函數的重載。

         那麼,先來看一道題:

C/C++學習之路(一)

         當我第一次看到這一道題的時候,我第一反應的答案是:9。然後看了一下答案,發現答案是4。于是乎我再一次翻看了構造函數的定義,才恍然大悟自己先前的想法是不對的。

         要想解決上面的問題,我們先要弄懂以下兩個問題:

         一、 構造函數是幹什麼的

class Counter

{

public:

         // 類Counter的構造函數

         // 特點:以類名作為函數名,無傳回類型

         Counter()

         {

                m_value = 0;

         }         

private:    

         // 資料成員

         int m_value;

}

         該類對象被建立時,編譯系統對象配置設定記憶體空間,并自動調用該構造函數->由構造函數完成成員的初始化工作

eg:    Counter c1;

        編譯系統為對象c1的每個資料成員(m_value)配置設定記憶體空間,并調用構造函數Counter( )自動地初始化對象c1的m_value值設定為0

故:

        構造函數的作用:初始化對象的資料成員。

         二、 構造函數的種類

class Complex

{         

private :

        double    m_real;

        double    m_imag;

        //    無參數構造函數

        // 如果建立一個類你沒有寫任何構造函數,則系統會自動生成預設的無參構造函數,函數為空,什麼都不做

        // 隻要你寫了一個下面的某一種構造函數,系統就不會再自動生成這樣一個預設的構造函數,如果希望有一個這樣的無參構造函數,則需要自己顯示地寫出來

        Complex(void)

        {

             m_real = 0.0;

             m_imag = 0.0;

        }         

        //    一般構造函數(也稱重載構造函數)

        // 一般構造函數可以有各種參數形式,一個類可以有多個一般構造函數,前提是參數的個數或者類型不同(基于c++的重載函數原理)

        // 例如:你還可以寫一個 Complex( int num)的構造函數出來

        // 建立對象時根據傳入的參數不同調用不同的構造函數

        Complex(double real, double imag)

             m_real = real;

             m_imag = imag;         

         }

        //    複制構造函數(也稱為拷貝構造函數)

        //    複制構造函數參數為類對象本身的引用,用于根據一個已存在的對象複制出一個新的該類的對象,一般在函數中會将已存在對象的資料成員的值複制一份到新建立的對象中

        //    若沒有顯示的寫複制構造函數,則系統會預設建立一個複制構造函數,但當類中有指針成員時,由系統預設建立該複制構造函數會存在風險,具體原因請查詢 有關 “淺拷貝” 、“深拷貝”的文章論述

        Complex(const Complex & c)

                // 将對象c中的資料成員值複制過來

                m_real = c.m_real;

                m_img    = c.m_img;

        }           

        // 類型轉換構造函數,根據一個指定的類型的對象建立一個本類的對象

        // 例如:下面将根據一個double類型的對象建立了一個Complex對象

        Complex::Complex(double r)

                m_real = r;

                m_imag = 0.0;

        }

        // 等号運算符重載

        // 注意,這個類似複制構造函數,将=右邊的本類對象的值複制給等号左邊的對象,它不屬于構造函數,等号左右兩邊的對象必須已經被建立

        // 若沒有顯示的寫=運算符重載,則系統也會建立一個預設的=運算符重載,隻做一些基本的拷貝工作

        Complex &operator=( const Complex &rhs )

                // 首先檢測等号右邊的是否就是左邊的對象本,若是本對象本身,則直接傳回

                if ( this == &rhs )

                {

                        return *this;

                }

                // 複制等号右邊的成員到左邊的對象中

                this->m_real = rhs.m_real;

                this->m_imag = rhs.m_imag;

               // 把等号左邊的對象再次傳出

               // 目的是為了支援連等 eg:    a=b=c 系統首先運作 b=c

               // 然後運作 a= ( b=c的傳回值,這裡應該是複制c值後的b對象)    

                return *this;

         下面使用上面定義的類對象來說明各個構造函數的用法:

void main()

        // 調用了無參構造函數,資料成員初值被賦為0.0

        Complex c1,c2;

        // 調用一般構造函數,資料成員初值被賦為指定值

        Complex c3(1.0,2.5);

        // 也可以使用下面的形式

        Complex c3 = Complex(1.0,2.5);        

        //    把c3的資料成員的值指派給c1

        //    由于c1已經事先被建立,故此處不會調用任何構造函數

        //    隻會調用 = 号運算符重載函數

        c1 = c3;        

        //    調用類型轉換構造函數

        //    系統首先調用類型轉換構造函數,将5.2建立為一個本類的臨時對象,然後調用等号運算符重載,将該臨時對象指派給c1

        c2 = 5.2;        

       // 調用拷貝構造函數( 有下面兩種調用方式)

        Complex c5(c2);

        Complex c4 = c2;  // 注意和 = 運算符重載區分,這裡等号左邊的對象不是事先已經建立,故需要調用拷貝構造函數,參數為c2

        當你了解了以上的内容是再看上面我出的題,就知道答案原來是這樣來的:

        a[4]是類數組,有4個對象,調用構造函數4次,而*p[5]是指針數組,也就是5個元素存放的是指向MyClass類型的對象的指針,沒有初始化的指針為空,不指向任何對象,也不調用構造函數。

        如果你懂了,我們再來看一道題:

繼續閱讀