十三、類的定義和實例化
1、類的語法形式
struct/class 類名:繼承表{
訪問控制限定符:
類名(形參表):初始化表{} //構造函數
~類名(void){} //析構函數
返回類型 函數名(形參表)[const]{} //成員函數
數據類型 變量名; //成員變量
}
2、訪問控制限定符
public:公有成員,在類的外部和內部都可以訪問的成員;
private:私有成員,只能在類的內部訪問的成員;
protected:保護成員,在類的內部和子類中可以訪問的成員;
eg:
struct/class {
eee; //struct默認公有成員,class默認私有成員
public:
aaa; //公有成員
private:
bbb; //私有成員
public:
ccc;
ddd;
};
3、構造函數(Constructor)
class 類名{
類名(形參表){} //構造函數
}
1)函數名和類名相同,沒有返回類型;
2)構造函數在對象被創建時自動被調用;
3)構造函數主要負責初始化對象,即初始化成員變量;
4、對象的創建和銷燬
1)在棧區創建單個對象
類名 對象(構造實參表);
類名 對象 = 類名(構造實參表);
注意:
如果構造函數沒有參數,類名 對象;
或類名 對象 = 類名();
2)在棧區創建對象數組
類名 對象數組[元素個數] = {類名(構造實參表), … };
3)在堆區創建單個對象
創建:
類名* 對象指針 = new 類名(構造實參表);
銷燬:
delete 對象指針
4)在堆區創建對象數組
創建:
類名* 對象指針 = new 類名[元素個數]{類名(構造實參表), ...}
銷燬:
delete[] 對象指針;
練習:實現一個電子時鐘,用構造函數接收當前系統時間,可以以秒爲單位運行;
class Clock{
public:
Clock(time_t t){ //time_t = long int;
tm* local = localtime(&t);
m_hour = local->tm_hour;
...
}
void run(void){
while(1){
//打印當前時間
printf("\r%02d:%02d:%02d", m_hour, m_min, m_sec);
// 刷新標準輸出緩衝區
fflush(stdout);
//計時加1
//sleep(1)
}
}
private:
int m_hour;
int m_min;
int m_sec;
};
int main(void)
{
//time(NULL):獲取當前系統的時間
Clock clock(time(NULL));
clock.run();
}
5、多文件編程
1)類的聲明部分放在xx.h文件中;
2)類的實現部分放在xx.cpp源文件中;
3)使用該類的代碼一般會在其它的文件中;
練習:將Clock類拆分成多文件形式;
十四、構造函數和初始化表
1、構造函數可以重載也可以帶有缺省參數
2、缺省構造函數
如果一個類沒有定義任何構造函數,編譯器會提供一個缺省構造函數(無參構造函數);
1)對於基本類型成員不做初始化;
2)對於類 類型成員變量,會自動調用相應類的無參構造函數來初始化;
注意:
如果定義了構造函數,無論是否有參數,編譯器都不會提供缺省構造函數了;
3、類型轉換構造函數(單參構造函數)
class 目標類型{
目標類型(源類型 src){...}
};
// 可以實現源類型到目標類型的隱式轉換
注意:
使用explicit(adj.外在的/ iks’plisit /)關鍵字修飾該構造函數,可以強制這種通過構造函數實現的類型轉換必須顯示的完成。
4、拷貝構造函數(重難點)
1)用一個已經存在的對象構造同類型的副本對象,會調用拷貝構造函數;
語法:
類名(const 類型& that){//完成成員的拷貝}
eg:
class A{
public:
A(const A& that){...}
};
A a1; // 無參方式構造a1
A a2(a1); // 調用拷貝構造函數來構造a2
A a2 = a1; // 和上面等價