蘇州專業(yè)做網(wǎng)站的公司有哪些在線代理瀏覽網(wǎng)站免費
目錄
一、類的6個默認成員函數(shù)
二、構(gòu)造函數(shù)
2.1 概念
2.2 特性
2.2.5 自動生成默認構(gòu)造函數(shù)
不進行顯示定義的隱患:
2.2.6 自動生成的構(gòu)造函數(shù)意義何在?
兩個棧實現(xiàn)一個隊列
2.2.7?無參的構(gòu)造函數(shù)和全缺省的構(gòu)造函數(shù)都稱為默認構(gòu)造函數(shù),并且默認構(gòu)造函數(shù)只能有一個。
2.4?一般情況,建議每個類,都可以寫一個全缺省的構(gòu)造(好用)
三、析構(gòu)函數(shù)
3.1 概念
3.2 特性
3.3 C++實現(xiàn)括號匹配和C語言的不同
一、類的6個默認成員函數(shù)
如果一個類中什么成員都沒有,簡稱為空類。
空類中真的什么都沒有嗎?并不是,任何類在什么都不寫時,編譯器會自動生成以下6個默認成員函數(shù)。
默認成員函數(shù):用戶沒有顯式實現(xiàn),編譯器會自動生成(半自動化)的成員函數(shù)稱為默認成員函數(shù)。
class Date {};
二、構(gòu)造函數(shù)
2.1 概念
對于以下Date類:
class Date
{
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;d1.Print();Date d2;d2.Print();return 0;
}
對于Date類,可以通過 Init 公有方法給對象設置日期,但如果每次創(chuàng)建對象時都調(diào)用該方法設置信息,未免有點麻煩,那能否在對象創(chuàng)建時,就將信息設置進去呢?
構(gòu)造函數(shù)是一個特殊的成員函數(shù),名字與類名相同,創(chuàng)建類類型對象時由編譯器自動調(diào)用,以保證每個數(shù)據(jù)成員都有 一個合適的初始值,并且在對象整個生命周期內(nèi)只調(diào)用一次。
2.2 特性
構(gòu)造函數(shù)是特殊的成員函數(shù),需要注意的是,構(gòu)造函數(shù)雖然名稱叫構(gòu)造,但是構(gòu)造函數(shù)的主要任務并不是開空間創(chuàng)建對象,而是初始化對象。
其特征如下:
- 函數(shù)名與類名相同。
- 無返回值。?
- 對象實例化時編譯器自動調(diào)用對應的構(gòu)造函數(shù)。
- 構(gòu)造函數(shù)可以重載。
class Date
{
public:// 1.無參構(gòu)造函數(shù)Date(){}// 2.帶參構(gòu)造函數(shù)Date(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};void TestDate()
{Date d1; // 調(diào)用無參構(gòu)造函數(shù)Date d2(2015, 1, 1); // 調(diào)用帶參的構(gòu)造函數(shù)// 注意:如果通過無參構(gòu)造函數(shù)創(chuàng)建對象時,對象后面不用跟括號,否則就成了函數(shù)聲明// 以下代碼的函數(shù):聲明了d3函數(shù),該函數(shù)無參,返回一個日期類型的對象// warning C4930: “Date d3(void)”: 未調(diào)用原型函數(shù)(是否是有意用變量定義的?)Date d3();
}
在C++中,當編譯器看到一個像Date d3();這樣的聲明時,它會根據(jù)語法規(guī)則將其解析為一個函數(shù)聲明,而不是一個對象定義。這是因為C++的語法允許這樣的歧義,而且函數(shù)聲明的優(yōu)先級高于對象定義。因此,即使你本意是想創(chuàng)建一個對象,編譯器也會將其視為一個函數(shù)聲明。為了避免這種歧義,最好不要在對象定義時使用空括號。?
2.2.5 自動生成默認構(gòu)造函數(shù)
?如果類中沒有顯式定義構(gòu)造函數(shù),則C++編譯器會自動生成一個無參的默認構(gòu)造函數(shù),一旦用戶顯式定義編譯器將不再生成。
class Date
{
public:/*// 如果用戶顯式定義了構(gòu)造函數(shù),編譯器將不再生成Date(int year, int month, int day){_year = year;_month = month;_day = day;}*/void Print(){cout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;
};int main()
{// 將Date類中構(gòu)造函數(shù)屏蔽后,代碼可以通過編譯,因為編譯器生成了一個無參的默認構(gòu)造函數(shù)// 將Date類中構(gòu)造函數(shù)放開,代碼編譯失敗,因為一旦顯式定義任何構(gòu)造函數(shù),編譯器將不再 生成// 無參構(gòu)造函數(shù),放開后報錯:error C2512: “Date”: 沒有合適的默認構(gòu)造函數(shù)可用Date d1;return 0;
}
在這個Date類的定義中,并沒有顯式定義任何構(gòu)造函數(shù)。編譯器會自動生成一個默認的無參構(gòu)造函數(shù)。這個自動生成的構(gòu)造函數(shù)不會進行任何實質(zhì)性的初始化操作。
不進行顯示定義的隱患:
class A
{
public:A(){_a = 0;}
private:int _a;
};class Time {
public:private:int _hour;int _minute;int _second;A _aa;
};class Date
{
public:void Print() {cout << _year << _month << _day << endl;}
private:// 默認生成構(gòu)造函數(shù)// 內(nèi)置類型沒有規(guī)定要處理(可處理,可不處理,看編譯器)int _year;int _month;int _day;// 自定義類型調(diào)用默認構(gòu)造函數(shù)Time _t;
};int main()
{//Date d1(2024, 4, 9);//d1.Print();Date d2;d2.Print();return 0;
}
2.2.6 自動生成的構(gòu)造函數(shù)意義何在?
關于編譯器生成的默認成員函數(shù),很多童鞋會有疑惑:不實現(xiàn)構(gòu)造函數(shù)的情況下,編譯器會生成默認的構(gòu)造函數(shù)。但是看起來默認構(gòu)造函數(shù)又沒什么用?d對象調(diào)用了編譯器生成的默認構(gòu)造數(shù),但是d對象_year/_month/_day,依舊是隨機值。也就說在這里編譯器生成的默認構(gòu)造函數(shù)并沒有什么用?
解答:C++把類型分成內(nèi)置類型(基本類型)和自定義類型。內(nèi)置類型就是語言提供的數(shù)據(jù)類型,如:int/char...,自定義類型就是我們使用class/struct/union等自己定義的類型,看看下面的程序,就會發(fā)現(xiàn)編譯器生成默認的構(gòu)造函數(shù)會對自定類型成員_t調(diào)用的它的默認成員函數(shù)。
class Time
{
public:Time(){cout << "Time()" << endl;_hour = 0;_minute = 0;_second = 0;}
private:int _hour;int _minute;int _second;
};
class Date
{
private:// 基本類型(內(nèi)置類型)int _year = 1970;int _month = 1;int _day = 1;// 自定義類型Time _t;
};
int main()
{Date d;return 0;
}
注意:C++11 中針對內(nèi)置類型成員不初始化的缺陷,又打了補丁,即:內(nèi)置類型成員變量在類中聲明時可以給默認值。
在實際應用中,通常建議在類的構(gòu)造函數(shù)中初始化這些成員,以確保對象的狀態(tài)是確定的。
兩個棧實現(xiàn)一個隊列
typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 10){_array = (DataType*)malloc(capacity * sizeof(DataType));if (nullptr == _array){perror("malloc申請空間失敗");return;}_size = 0;_capacity = capacity;}void Push(const DataType& data){// CheckCapacity();_array[_size] = data;_size++;}~Stack(){if (_array){free(_array);_array = nullptr;_capacity = 0;_size = 0;}}
private:DataType* _array;size_t _size;size_t _capacity;
};
// 自動生成的構(gòu)造函數(shù)意義何在?
class MyQueue
{
private:Stack _pushst;Stack _popst;
};int main()
{MyQueue q;return 0;
}
自動生成的構(gòu)造函數(shù)意義何在??
- 確保成員變量的正確初始化:自動生成的構(gòu)造函數(shù)會調(diào)用成員變量的默認構(gòu)造函數(shù),確保 MyQueue 中的兩個 Stack 對象在 MyQueue 對象創(chuàng)建時被正確初始化。
- 簡化代碼:由于 MyQueue 類在這個例子中沒有特殊的初始化需求,因此不需要手動編寫構(gòu)造函數(shù)。
- 如果類中沒有需要特別處理的初始化邏輯,那么自動生成的構(gòu)造函數(shù)可以簡化代碼,避免不必要的冗余。這樣,開發(fā)者可以專注于類的其他功能和邏輯,而不必擔心基本的初始化問題。?
2.2.7?無參的構(gòu)造函數(shù)和全缺省的構(gòu)造函數(shù)都稱為默認構(gòu)造函數(shù),并且默認構(gòu)造函數(shù)只能有一個。
注意:無參構(gòu)造函數(shù)、全缺省構(gòu)造函數(shù)、我們沒寫編譯器默認生成的構(gòu)造函數(shù),都可以認為是默認構(gòu)造函數(shù)。
class Date
{
public:Date(){_year = 1900;_month = 1;_day = 1;}Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};
// 以下測試函數(shù)能通過編譯嗎?
void Test()
{Date d1;
}
2.4?一般情況,建議每個類,都可以寫一個全缺省的構(gòu)造(好用)
class Date
{
public:// 他們倆構(gòu)成函數(shù)重載,但是無參調(diào)用時會存在歧義/*Date(){_year = 1;_month = 1;_day = 1;}*/// 一般情況,建議每個類,都可以寫一個全缺省的構(gòu)造(好用)Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//void Init(int year, int month, int day)//{// _year = year;// _month = month;// _day = day;//}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}private:int _year; // 年int _month; // 月int _day; // 日
};int main()
{//Date d1(); 無法跟函數(shù)聲明區(qū)分開Date d1;d1.Print();Date d2(2024, 4, 2);// 對象(參數(shù)列表)d2.Print();Date d3(2024);d3.Print();Date d4(2024, 4);d4.Print();return 0;
}
三、析構(gòu)函數(shù)
3.1 概念
通過前面構(gòu)造函數(shù)的學習,我們知道一個對象是怎么來的,那一個對象又是怎么沒呢的?析構(gòu)函數(shù):與構(gòu)造函數(shù)功能相反,析構(gòu)函數(shù)不是完成對對象本身的銷毀,局部對象銷毀工作是由編譯器完成的。而對象在銷毀時會自動調(diào)用析構(gòu)函數(shù),完成對象中資源的清理工作。
3.2 特性
析構(gòu)函數(shù)是特殊的成員函數(shù),其特征如下:?
- 析構(gòu)函數(shù)名是在類名前加上字符 ~。?
- 無參數(shù)無返回值類型。?
- 一個類只能有一個析構(gòu)函數(shù)。若未顯式定義,系統(tǒng)會自動生成默認的析構(gòu)函數(shù)。注意:析構(gòu)函數(shù)不能重載
- 對象生命周期結(jié)束時,C++編譯系統(tǒng)系統(tǒng)自動調(diào)用析構(gòu)函數(shù)。
typedef int DataType;class Stack
{
public:Stack(size_t capacity = 3){cout << "Stack(size_t capacity = 3)" << endl;_array = (DataType*)malloc(sizeof(DataType) * capacity);if (NULL == _array){perror("malloc申請空間失敗!!!");return;}_capacity = capacity;_size = 0;}void Push(DataType data){// CheckCapacity();_array[_size] = data;_size++;}// 其他方法...~Stack(){cout << "~Stack()" << endl;if (_array){free(_array);_array = NULL;_capacity = 0;_size = 0;}}
private:DataType* _array;int _capacity;int _size;
};int main()
{Stack st;return 0;
}
5. 關于編譯器自動生成的析構(gòu)函數(shù),是否會完成一些事情呢?下面的程序我們會看到,編譯器生成的默認析構(gòu)函數(shù),對自定類型成員調(diào)用它的析構(gòu)函數(shù)。
class Time
{
public:~Time(){cout << "~Time()" << endl;}
private:int _hour;int _minute;int _second;
};
class Date
{
private:// 基本類型(內(nèi)置類型)int _year = 1970;int _month = 1;int _day = 1;// 自定義類型Time _t;
};
int main()
{Date d;return 0;
}
程序運行結(jié)束后輸出:~Time()
在main方法中根本沒有直接創(chuàng)建Time類的對象,為什么最后會調(diào)用Time類的析構(gòu)函數(shù)?
因為:main方法中創(chuàng)建了Date對象d,而d中包含4個成員變量,其中_year, _month, _day三個是內(nèi)置類型成員,銷毀時不需要資源清理,最后系統(tǒng)直接將其內(nèi)存回收即可;而_t是Tim類對象,所以在d銷毀時,要將其內(nèi)部包含的Time類的_t對象銷毀,所以要調(diào)用Time類的析構(gòu)函數(shù)。但是:main函數(shù)中不能直接調(diào)用Time類的析構(gòu)函數(shù),實際要釋放的是Date類對象,所以編譯器會調(diào)用Date類的析構(gòu)函數(shù),而Date沒有顯式提供,則編譯器會給Date類生成一個默認的析構(gòu)函數(shù)。
目的是:在其內(nèi)部調(diào)用Time類的析構(gòu)函數(shù),即當Date對象銷毀時,要保證其內(nèi)部每個自定義對象都可以正確銷毀,main函數(shù)中并沒有直接調(diào)用Time類析構(gòu)函數(shù),而是顯式調(diào)用編譯器為Date類生成的默認析構(gòu)函數(shù)
注意:創(chuàng)建哪個類的對象則調(diào)用該類的析構(gòu)函數(shù),銷毀那個類的對象則調(diào)用該類的析構(gòu)函數(shù)?
6. 如果類中沒有申請資源時,析構(gòu)函數(shù)可以不寫,直接使用編譯器生成的默認析構(gòu)函數(shù),比如Date類;有資源申請時,一定要寫,否則會造成資源泄漏,比如Stack類。
3.3 C++實現(xiàn)括號匹配和C語言的不同
?可以明顯的看出,C++對應C語言來說簡化了不少,對C語言進行了一定的優(yōu)化。
今天就先到這了!!!
看到這里了還不給博主扣個:
?? 點贊??收藏 ?? 關注!
你們的點贊就是博主更新最大的動力!
有問題可以評論或者私信呢秒回哦。