建構子(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的方式assignment給james:
james.age = temporary.age ;
james.number = temporary.number;
注意到了沒有,number是const的,能做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; ==>fNum為flaot的型態,要assignment給int型態的iNum,要如何做轉換呢? (1)以fNum的值,產生並初始化一個暫時的臨時物件,型態為int (2)將這個臨時物件assignment給iNum
如果瞭解之後,接著來看james=10;這一行轉換的過程: (1)以10的值,產生並初始化一個暫時的臨時物件,型態為People ==>可以視為這樣People temporary(10); ==>所以它會呼叫People(int _age){...}這個Constructor ==>此時temporary的內容 temporary.age = 10; temporary.number=2; (2)接著將這個臨時物件assignment給james,由於我並沒有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