建構子(constructor)

建構子是什麼呢?建構子是從什麼樣的觀念演化過來的呢?不曉得沒有關係,現在一步一步

帶你走進它的歷史。假設對
C++的認知中,類別(class)中只存在函數與變數,而沒有什麼所謂

的建構子
(constructor)、解構子(destructor)等,那要如何撰寫這個類別呢?舉個例子:

::::::::::::::::::::::::::::::::::::::::::::::

#include<iostream>
using namespace std;

class People
{
    private:
        int age;

    public:
        void Initial(int _age)
        {
            age = _age;
        }

        int GetAge( ) 
        {
            return age;
        }
};

void main( )
{
    People james;
    
    james.Initial(20);

    cout<<"James's age : "<<james.GetAge( )<<endl;
}

::::::::::::::::::::::::::::::::::::::::::::::

輸出:James's age : 20

Initial(...)這個函數從字面上應該就可以知道它的作用,就是初始化但你會不會覺得很麻煩呢?

在宣告的時候為什麼不一起初始化它,而要呼叫Initial(...)來初始化呢?我想這個問題不只我想

到,你應該也觀察到了,所以在C++中,使用了一個特別的成員函數(Special member function)

來產生(Create)並初始化(Initialize)物件(Object),這個特別的成員函數,稱之為建構子(Constructor)

舉個例子:

::::::::::::::::::::::::::::::::::::::::::::::

#include<iostream>
using namespace std;

class People
{
    private:
        int age;

    public:
        People()
        {
            cout<<"Constructor!!!"<<endl;
        }
};

void main( )
{
    People james;    

}

::::::::::::::::::::::::::::::::::::::::::::::
輸出:Constructor!!!

在宣告變數james,會去呼叫建構子People(),而輸出"Constructor!!!"

有沒有注意到,建構子People()與類別同名(Same Name as the class)!

這是建構子的語法之一,另外發現到了嗎?建構子沒有回傳值(No Return Value)

這也是建構子的語法之一,另外有沒有發現到建構子參數列(Parameter list)中,

沒有任何的參數,那就不是建構子的語法囉!!!那是因為還沒有討論到,慢慢來!!!

上一個例子,沒有做任何初始化的動作,接下來看個有初始化的例子:

::::::::::::::::::::::::::::::::::::::::::::::

#include<iostream>
using namespace std;

class People
{
    private:
        int age;

    public:
        People(int _age) 
        {
            cout<<"Constructor!!!"<<endl ;
            age = _age ;
        }
        
        void Display()
        {
            cout<<"Age :"<<age<<endl;
        }

};

void main( )
{
    People james(20);   
    
    james.Display();
}

::::::::::::::::::::::::::::::::::::::::::::::
輸出:
Constructor!!!
Age :20

建構子People(...),具有一個參數用來初始化資料成員(Data member)age

當一開始執行時People james(20);時,呼叫建構子,輸出"Constructor!!!"

並將_age = 20 的值指定給資料成員age,建構子呼叫結束,之後執行james.Display顯示age的值。

說明:

(1)

    People james(20);在此可以改寫為: People james = 20;

   這是一個Equivalent Syntax,而不是Assignment Statement.

   這似乎會難人感到些許的困惑,會讓人把"="看作是Assignment

   不管你是否喜歡這種用法,你必須看得懂.

   Assignment Statement是什麼呢?舉個例子:  num1 = num2;

(2)   

 一個參數的建構子(One-Argument Constructor),另一個名稱為轉換函數(Conversion function)

它將另一個資料型態轉成另一個資料型態:

People james(20);    //建構子將整數型態數值20轉換成People的資料型態

除了一個參數的建構子外,當然還有Two-Argument Constructor, No-Argument Constructor,...等,

觀念是一樣的。接著來介紹複製建構子(Copy constructors),那它什麼時候會被呼叫呢?當以一

個已存在的object來產生並初始化另一個object時,Copy constructor會被呼叫,而什麼場合的時候

會被呼叫呢?常見的兩個場合:

(1)Pass by Value的方式

(2)Return by Value的方式

很模糊吧!!!別急,先來看看Copy constructor的型式,舉個例子:

::::::::::::::::::::::::::::::::::::::::::::::

#include<iostream>
using namespace std;
class People
{
    private:
        int age;
    public:
        People(int _age)  
	{
		cout<<"Constructor!!!"<<endl ;
		age = _age ;
	}
	People(const People& _People)
	{
		cout<<"Copy Constructor!!!"<<endl;
		age = _People.age;
	}
	void Display()
	{
		cout<<"Age :"<<age<<endl;
	}
};
void main( )
{
    	People james=20;	//Calling the constructor!!!
	People tkd = james;	//Calling copy constructor to create tkd
	
	james.Display();
	tkd.Display();
}
::::::::::::::::::::::::::::::::::::::::::::::
輸出:
Constructor!!!
Copy Constructor!!!
Age :20
Age :20

Copy constructor的型式People(const People& _People);

(1)參數必須以Pass by Reference的方式

若以Pass by Value的方式會有什麼結果呢?

那來研究看看Copy constructorPass by Value的方式。

執行到People tkd = james;

tkd呼叫Copy constructor:
People(const People _People){ ... }
,此時james傳給_People:
^^^^^^^^^^^^^^^^^^
const People _People = james;

此時_People呼叫Copy constructor
People(const People _People){ ... }
,此時將james傳給_People:
^^^^^^^^^^^^^^^^^^
const People _People = james;

此時_People呼叫Copy constructor

...infinite(一直執行到電腦的堆疊溢位或是發生錯誤)

所以以Pass by Value的方式是不被compiler許可的,各位不妨試試看。

那什麼是Pass by Reference呢?如果還不知道,那你應該不適合看此文章囉!!!

(2)參數應該是const,因為你只是利用已存在的object來產生並初始化object

而不應該改變已存在的object內的內容!!!

來介紹什麼場合會呼叫Copy constructor,舉個例子:

::::::::::::::::::::::::::::::::::::::::::::::
#include<iostream>
using namespace std;

class People
{
    private:
        int age;
    public:
        	People(int _age)  
	{
		cout<<"Constructor!!!"<<endl ;
		age = _age ;
	}
	People(const People& _People)
	{
		cout<<"Copy Constructor!!!"<<endl;
		age = _People.age;
	}
	void Display()
	{
		cout<<"Age :"<<age<<endl;
	}
};
void func(People _People){}

void main( )
{
	People james=20;
	
	james.Display();
	func(james);	
}
::::::::::::::::::::::::::::::::::::::::::::::
輸出:
Constructor!!!
Age :20
Copy Constructor!!!

當呼叫func函數時void func(People _People){}
                                         
People _People = james;

會呼叫Copy constructor!!!

再舉個例子:

::::::::::::::::::::::::::::::::::::::::::::::
#include<iostream>
using namespace std;

class People
{
    private:
        int age;
    public:
	People()
	{
		cout<<"Default Constructor!!!"<<endl;
	}
        	People(int _age)  
	{
		cout<<"Constructor!!!"<<endl ;
		age = _age ;
	}
	People(const People& _People)
	{
		cout<<"Copy Constructor!!!"<<endl;
		age = _People.age;
	}
	void Display()
	{
		cout<<"Age :"<<age<<endl;
	}
};
People func()
{	
	People temp;
	return temp;
}
void main( )
{
   	People james=20;
	james.Display();
	func();
}
::::::::::::::::::::::::::::::::::::::::::::::
輸出:
Constructor!!!
Age :20
Default Constructor!!!
Copy Constructor!!!

呼叫func()時,為什麼會呼叫Copy Constructor呢?重點在於return temp

注意看func()回傳值的傳遞方式是以return by value,所以return時會copy

一份temp的值儲存在一個臨時物件(temporary object),此時會呼叫Copy

Constructor!!在如果將func()的內容改為這樣:

People func()
{
    return People(10);
}

那請問各位是會呼叫Copy Constructor還是Constructor呢?你應該答得出來滴!!!
Ans:Constructor!!!

回目錄
Written By James On 2004/02/08 
 
Hosted by www.Geocities.ws

1