建構子(constructor)

問題討論:

先來看看這個程式:

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

#include<iostream>
using namespace std;

class People
{
    private:
        int age;
   
     const int number;
        static int total;
    public:
        People(int _age):number(++total)  
       {
            cout<<"Constructor!!!"<<endl ;
            age = _age ;
        }

        People(const People& _People):number(++total)   
        {
            cout<<"Copy Constructor!!!"<<endl;
            age = _People.age;
        }

        void Display()
        {
            cout<<" Age :"  <<age
                 <<" Number:"<<number
                 <<endl;
        }

        void SetAge(int _age)
        {
            age = _age;
        }
};
int People::total=0;

void main( )
{
    	People james=20;
	
	james = 10;
}

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

這個程式那裡有問題呢?來看看james=10;這一行囉!!!
10
會先轉換成型態為People暫時的臨時物件(temporary object),也因為產生暫時的物件
所以會呼叫
Constructor!!接著由於沒有撰寫overloading assignment operator,所以
compiler會以memberwise的方式assignmentjames:

james.age = temporary.age ;
james.number = temporary.number;

注意到了沒有,numberconst的,能做assignment的動作嗎?不行吧!!!
所以編譯器會告訴你編譯不成功!!!我猜測是這個原因!!!
為了能讓它通過,我先將const拿掉,當然你可以overloading assignment operator
我先以拿掉
const來解決這個問題,並加入幾行的程式:

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

#include<iostream>
using namespace std;
class People
{
    private:
		int age;
		int number;
		static int total;
    public:
     
		People(int _age):number(++total)  
		{
			cout<<"Constructor!!!"<<endl ;
			age = _age ;
		}
		People(const People& _People):number(++total)
		{
			cout<<"Copy Constructor!!!"<<endl;
			age = _People.age;
		}
		void Display()
		{
			cout<<" Age :"  <<age
			      <<" Number:"<<number
			      <<endl;
		}
};
int People::total=0;
void main( )
{
 	People james=20;
	james.Display();
	james = 10;
	james.Display();
}

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

輸出:
Constructor!!!
 Age :20 Number:1
Constructor!!!
 Age :10 Number:2
這個程式不是只有一個object:james嗎?這麼輸出Number會是2呢?
發現問題了沒呢?相信你發現到了,我在上個例子中有描述過,沒發現到
沒關係,慢慢學,先瞭解轉換(Conversion)的過程是什麼,舉個例子:
float fNum=10.5f;
int iNum;
iNum = fNum;	
==>fNumflaot的型態,要assignmentint型態的iNum,要如何做轉換呢?
   (1)fNum的值,產生並初始化一個暫時的臨時物件,型態為int
    (2)將這個臨時物件assignmentiNum
如果瞭解之後,接著來看james=10;這一行轉換的過程:
(1)10的值,產生並初始化一個暫時的臨時物件,型態為People
   ==>可以視為這樣People temporary(10);
   ==>所以它會呼叫People(int _age){...}這個Constructor
   ==>此時temporary的內容
      temporary.age = 10;
         temporary.number=2;
(2)接著將這個臨時物件assignmentjames,由於我並沒有overloading assignment operator
   ,所以是以memberwise assignment的方式來做assignment的動作:
   james.age = temporary.age;
    james.number = temporary.number;
   所以此時物件james兩個data member的內容為:
   age ==>10;
    number ==>2;
輸出的結果就是這樣產生的,這樣對嗎?結果是不正確的,為了避免single parameter
constructor被做為型別轉換之用,所以C++中有一個關鍵字explicit來處理這個狀況,
當Constructor前加上explicit時,這個Constructor是不能被用為Type Conversion之用
也可以說無法以assignment的方式呼叫Constructor,而必須以explicit的方式來呼叫
Constructor,先來看一下修改後的例子:
::::::::::::::::::::::::::::::::::::::::::::::
#include<iostream>
using namespace std;
class People
{
    private:
		int age;
		int number;
		static int total;
    public:
     
		explicit People(int _age):number(++total)  
		{
			cout<<"Constructor!!!"<<endl ;
			age = _age ;
		}
		People(const People& _People):number(++total)
		{
			cout<<"Copy Constructor!!!"<<endl;
			age = _People.age;
		}
		void Display()
		{
			cout<<" Age :"  <<age
			    <<" Number:"<<number
			    <<endl;
		}
};
int People::total=0;
void main( )
{
	//People james=20;
	People james(20);
}
::::::::::::::::::::::::::::::::::::::::::::::
如果People james=20;不改的話,編譯器應該會顯示convert的問題!!為什麼呢?
不是說People james(20); 作用等於People james=20;嗎?若在未介紹explicit這
個關鍵字之前,的確是對的,但介紹explicit之後,你應該曉得為什麼了吧!!!
因為People james=20;需要做轉換的動作唷!!!
那問題來了!!!那不就不能做assignment的動作了嗎?嘿嘿!!!此時C++還提供你一項
運算子多載(Operator Overloading)的技術,這麼使用呢?不急,先看個例子:
::::::::::::::::::::::::::::::::::::::::::::::
#include<iostream>
using namespace std;

class People
{
    private:
	int age;
	int number;
	static int total;
    public:
	explicit People(int _age):number(++total)  
	{
		cout<<"Constructor!!!"<<endl ;
		age = _age ;
	}
	People(const People& _People):number(++total)
	{
		cout<<"Copy Constructor!!!"<<endl;
		age = _People.age;
	}
	People& operator= (const int _age)
	{
		age = _age;
		return *this;
	}
	void Display()
	{
		cout<<" Age :"  <<age
		    <<" Number:"<<number
		    <<endl;
	}
};
int People::total=0;
void main( )
{
	People james(20);
	james.Display();
	james = 30;
	james.Display();
}
::::::::::::::::::::::::::::::::::::::::::::::
輸出:
Constructor!!!
 Age :20 Number:1
 Age :30 Number:1
這個寫法只適用於整數,若有其它型態的話,需另外再寫哦!!
那有關於Operator Overloading的使用方法,那......!!!
回目錄
Written By James On 2004/02/08 
 
Hosted by www.Geocities.ws

1