構造函數和析構函數
15. 類和對象的關系。
它們之間的區別就像是整型和整型變量之間的區別一樣。我們可以定義多個整型變量,例如 int a,b,c;,并且可以為整型變量賦值。但是不能夠為整型賦值。類和對象也是一樣的。對象是類的實例化,我們可以為對象賦值,但是不能為類賦值。類只是告訴編譯器,在定義對象時如何在內存中為對象分配空間。
16. 構造函數和析構函數的調用。
在 C++中,不能通過構造函數或析構函數名稱來直接構建或釋放對象。當定義一個對象時會自動調用構造函數。例如:
CBook book; //在棧中構建對象
CBook *pBook = new CBook(); //在堆中構建對象
上述兩行代碼都會調用構造函數。對于析構函數來說,當對象是在棧中構建時,作用域消失會自動調用析構函數。而在堆中構建對象時,當調用 delete 運算符釋放對象會導致析構函數被調用。
總之,構造函數在創建類對象的時候被自動調用,析構函數在使用 delete 運算符或類對象生命期結束時,由系統自動調用。
17. 代碼膨脹
下面的代碼有哪些不足之處?
class CBook //定義一個 CBook 類
{
public:
double m_Price; //定義數據成員
char *m_BookName;
char *m_Press;
CBook() //默認構造函數
{
m_BookName = new char[128];
m_Press = new char[128];
memset(m_BookName, 0, 128);
memset(m_Press, 0, 128);
strcpy(m_BookName, "Visual C++");
strcpy(m_Press, "電子工業");
m_Price = 0.0;
}
~CBook() //析構函數
{
//...
delete [] m_BookName;
delete [] m_Press;
}
};
int main(int argc, char* argv[])
{
CBook book; //定義一個 CBook 類對象 book
int state = 0; //定義一個整型變量
switch(state)
{
case 0: //分支判斷
{
printf("%s\n",book.m_BookName); //輸出信息
return 0; //函數結束
}
case 1: //分支判斷
{
printf("%f\n",book.m_Price); //輸出信息
return 0; //函數結束
}
default: //默認情況
return 0; //函數結束
}
return 0;
}
由于 CBook 類的析構函數是內聯成員函數,因此上述代碼在每一個 return 語句之前,析構函數均會被展開。因為 return 語句表示當前函數調用結束,book 對象的生命期也就結束了,自然調用其析構函數。根據上述分析,main 函數中 switch 語句的編寫是非常不明智的,下面對其進行修改,將 return 語句替換為 break 語句。
int main(int argc, char* argv[])
{
CBook book; //定義一個 CBook 類對象 book
int state = 0; //定義一個整型變量
switch(state)
{
case 0: //分支判斷
{
printf("%s\n",book.m_BookName); //輸出信息
break; //函數結束
}
case 1: //分支判斷
{
printf("%f\n",book.m_Price); //輸出信息
break; //函數結束
}
default: //默認情況
break; //函數結束
}
return 0;
}
18. 轉換函數
請完成下面代碼實現 main 函數中的類型轉換(不能使用運算符重載)。
class CPerson
{
public:
int m_nAge;
CPerson()
{
m_nAge = 0;
}
};
int main(int argc, char* argv[])
{
CPerson person = 10; //將該語句合法化
return 0;
}
構造函數有一個特殊的功能,就是實現類型轉換。但是要求構造函數必須只能有一個參數。當該類型的參數賦值給類對象時,將實現類型轉換。這樣的構造函數也被稱為轉換函數。
通過構造函數來實現類型轉換。修改 CPerson 類的構造函數,使其包含
一個整數作為參數。例如:
CPerson(intAge)
{
m_nAge = Age;
}
這樣,main 函數中的“CPerson person = 10;”語句就合法了。
19. C++ 中的 explicit 關鍵字有何作用?
explicit 關鍵字的作用是禁止將構造函數作為轉換函數。例如,如果一個類的構造函數中只包含一個整型參數,在構造函數前使用 explicit 關鍵字可以阻止像 CPerson person = 10;
這樣的語句執行,導致編譯錯誤。
20. 調用構造函數
以下代碼中輸出結果是 0 嗎,為什么?
struct A
{
int m_i;
A( int i )
: m_i(i)
{
//...
}
A()
{
A(0);
}
};
int main(int argc, char* argv[])
{
A object;
cout << object.m_i << endl;
return 0;
}
在 C++中,如果確定了某一個構造函數創建對象,在構造函數中如果調用其他重載的構造函數,它再不會執行其他構造函數的初始化部分代碼,而是執行函數體部分的代碼。
不會是 0 。因為在默認構造函數中調用一個內部的帶參數的構造函數是用戶的行為,而不是編譯器的行為,就像是調用普通的函數一樣,它不會執行構造函數的初始化部分。因此輸出結果不會是 0 。
參考資料:
C++ explicit關鍵字詳解