第十三章_类和对象
目錄
1.strcpy和memcpy的區別
2.exit
一、基本概念1
1.類的封裝性
2.定義一個類?
?3.成員函數 類中聲明,類外實現?
二、構造函數
1. 構造函數 和 析構函數
2. 構造函數 的 概述
3. 構造函數 的 定義方法
三、析構函數
?1.析構函數的定義方法
2.析構函數的調用順序
?四、拷貝構造函數
1.拷貝構造的定義形式
2.拷貝構造 和 無參構造、有參構造 的關系
3.拷貝構造的幾種調用形式?
?4.拷貝構造的深拷貝
?五、初始化列表
1.對象成員
?2.初始化列表
?六、explicit關鍵字
七、類的對象數組
?八、動態對象創建
1. c創建動態對象
九、靜態成員
1.靜態成員變量?
?2.靜態成員函數?
3.單例模式設計?
?十、c++面向對象模型
?1.成員變量 和 函數的存儲
?2.this指針
2.2 this指針的應用
十一、友元
1.普通全局函數 作為 類的友元
2.類的某個成員函數 作為另一個類的友元
?3.友員注意事項
4.友員案例
十二、運算符重載
1.基本概念
2.可以重載的運算符
3.重載 輸出運算符?
4.重載 輸入運算符?
5.重載 加法運算符?
6.重載 相等運算符?
7.重載 加加減減 運算符?
8.重載 函數調用運算符
?9.智能指針(指針運算符(*、->)重載)
插入:
1.strcpy和memcpy的區別:
(頭文件都是<string.h>)
?1、復制的內容不同。 strcpy只能復制字符串,而memcpy可以復制任意內容,例如字符數組、整型、結構體、類等。
2、復制的方法不同。 strcpy不需要指定長度,它遇到被復制字符的串結束符"0"才結束,所以容易溢出。 memcpy則是根據其第3個參數決定復制的長度。
int* tmp = new int[capacity];? ? ? ? ? ? ? ? ? ? //申請空間
memset(tmp, 0, sizeof(int) ?* capacity);? //tmp每個元素賦值0,即 清空空間
memcpy(tmp, arr, sizeof(int) * size);? ? ? ?//arr的內容拷貝到tmp,指定大小(arr的size)13
strcpy(tmp,arr);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//arr的內容拷貝到tmp
2.exit
進程的退出最好是用三個終止函數( exit、_exit、 _Exit )其中的一個(后兩者屬于系統調用),當然建議 exit 即可
正常退出:exit(0)、exit( )
異常退出:exit(除0外的其他值)
0/其他值 表示退出狀態,即把退出狀態傳給exit函數,正常和異常 表現為后期操作系統內部處理過程不同,但最后都會退出。
完整寫是system.exit( );
一、基本概念1
1.類的封裝性
類 將具有共性的 數據和方法 封裝在一起,加以權限區分,用戶只能通過 公共方法 訪問 私有數據。
類的權限分為:private(私有)、protected(保護)、public(公有)
在類的外部,有public修飾的成員才可以被訪問。在沒有涉及繼承和派生時,private和protected是同等級的,外部不允許訪問。用戶在類的外部 可以通過public方法 間接訪問 private和protected是數據。
2.定義一個類?
?class關鍵字(注意有分號)
class Data { //成員變量 private: //類中不寫權限默認private(私有) int a; protected: int b; public: int c;//成員方法 void showData(void) {cout<<a<<b<<c<<endl;}};int main() { //類實例化一個對象 Data ob; //類外不能直接訪問 類的私有和保護數據,公有數據可以。 cout<<ob.c<<endl; //類中的成員函數和成員變量,需要對象調用。 ob.showData(); }?設計一個類的步驟:
- 確定有哪些成員變量,成員變量為私有
- 確定操作這些變量的成員函數,成員函數為公有(Init函數+get函數+其他)
?3.成員函數 類中聲明,類外實現?
?注意成員函數要加 ::,以表明所屬,和全局函數區分
一般都是?成員函數 類中聲明,類外實現?,類定義在.h文件,成員函數實現在.cpp文件
*成員函數 一般比 全局函數 傳的參數要少
? ? ?成員函數需要用某個成員變量去調用,傳參時無需再傳這個成員變量,因此參數變少。
二、構造函數
1. 構造函數 和 析構函數
構造函數 完成 初始化操作,析構函數 完成 清理操作。這2個函數都會被編譯器自動調用。??
2. 構造函數 的 概述
類實例化對象的時候,系統自動調用構造函數,完成對象初始化。
如果用戶不提供構造函數,編譯器會自動添加一個默認的構造函數(空函數)。
如果用戶定義了一個構造函數(不管是有參還是無參),編譯器都不再提供構造函數。
(這也就意味著,如果定義了一個有參構造函數,但是定義了一個無參的類的話,編譯器將因找不到無參構造函數而報錯)
3. 構造函數 的 定義方法
構造函數名 和 類名 相同,沒有返回值(連void都不可以),可以有參數,可以重載。權限為public(因為肯定要外部傳初始值,私有就無法調用了)?
class Data{ public: int mA; public: //無參構造函數 Data() {mA=0;} //有參構造函數 Data(int a) {mA=a;} //析構函數 ~Data() {cout<<mA<<endl;} };int main(){ //隱式調用無參構造函數(編譯器自動調用)(推薦) Data ob1; //顯式調用無參構造函數 Data ob2=Data();//這里其實也是先創建匿名對象,再把匿名對象的值賦給對象ob2 //隱式調用有參構造函數(推薦) Data ob3(10); //顯式調用有參構造函數 Data ob4=Data(10);//匿名對象(無參) //當前語句結束,立即釋放 Data(); Data(20);//構造函數隱式轉換(當 類中只有一個數據成員 時才可以這樣直接賦值) Data ob5=100;三、析構函數
?1.析構函數的定義方法
- 函數名和類名稱相同,在函數名前加~,沒有返回值類型,沒有函數形參(不能被重載)。
- 當對象生命周期結束的時候,系統自動調用析構函數。
- 一般情況下,系統默認的空的析構函數就足夠,不需要再寫析構函數;
- 但如果一個類有 指向堆區空間的 指針成員,這個類必須寫析構函數。
(因為析構函數只釋放了指針變量,沒有釋放指針變量所指的堆區空間。需要寫析構函數去釋放指針成員所指向的堆區空間)
(示例見上)
2.析構函數的調用順序
棧,先定義的后釋放
?四、拷貝構造函數
本質:有參構造函數?
拷貝構造的調用時機:舊對象給新對象初始化,就會調用拷貝構造函數。
如果用戶不提供拷貝構造,編譯器會自動提供一個默認的拷貝構造,完成賦值動作(淺拷貝)。
只有存在指針成員變量,需要深拷貝時,才會去自己寫拷貝構造函數。
1.拷貝構造的定義形式
名字 同 類名稱,參數 是 當前類的常引用(特征)
?
2.拷貝構造 和 無參構造、有參構造 的關系
如果用戶定義了 拷貝構造 或者 有參構造,都會屏蔽 無參構造。
如果用戶定義了 無參構造 或者 有參構造,不會屏蔽 拷貝構造。
3.拷貝構造的幾種調用形式?
3.1舊對象給新對象初始化
?
3.2普通對象作為 函數參數,調用函數時
3.3普通對象 作為 函數返回值 ,返回值時
vs會發生拷貝構造:
Qtcreater、linux不會發生拷貝構造:
用ob2直接接管ob1空間,而不需要臨時匿名對象(即ob1空間沒被釋放,直接給ob2了)
3.4給對象取別名,不會調用拷貝構造
?
?4.拷貝構造的深拷貝
如果類中沒有指針成員,不用實現 拷貝構造 和 析構函數?。
如果類中有 指針成員 且指向堆區空間,必須實現 析構函數 釋放指針成員指向的堆區空間,并且必須實現 拷貝構造 完成深拷貝。
?五、初始化列表
1.對象成員
- 在類中定義的成員變量一般是基本的數據類型,但 類中成員 也可以是 對象。
- 先調用對象成員的構造函數,再調用本身的構造函數。
- 析構函數 和 構造函數調用順序相反,先構造后析構(棧,先進后出)。?
- 類 會自動調用?對象成員的 無參構造。當 類 想調用對象成員的?有參構造,必須使用 初始化列表。?
?2.初始化列表
三種類型必須通過初始化列表來初始化 :
(1)類中成員 是 對象 + 類 想調用對象成員 有參構造,必須使用?初始化列表。(想給對象成員自定義初始化值時)
(2)引用類型?
(3)常量?
#include<iostream> using namespace std; class A { public:int mA; public:A() { mA = 0; cout << "A類無參構造" << endl; }A(int a) { mA = a; cout << "A類有參構造" << endl; }~A() { cout << "A類析構函數" << endl; }}; class B { public:int mB;A ob; public:B() { cout << "B類的無參構造" << endl; } //初始化列表B(int a, int b) :ob(a) { //ob.mA = a; (不寫:ob(a) ,寫這個也可以) mB = b; cout << "B類有參構造" << endl; }~B(){ cout << "B析構函數" << endl;}}; int main(int argc,char *argv[]) {B ob1(10, 20);cout << "mA=" << ob1.ob.mA << ",mB=" << ob1.mB << endl;return 0; }?六、explicit關鍵字
針對:單參數的構造函數;或者除了第一個參數外,其它參數都有默認值的 多參構造函數
作用:修飾構造函數,防止隱式轉換。
?隱式轉換 和 隱式調用 不一樣。隱式調用 見上面 構造函數的定義方法。
class MyString{ public: explict MyString(int n){cout<<"MyString(int n)"<<endl;} MyString(const char* str){cout<<"MyString(const char* str)"<<endl;} }; int main(){ //MyString str1=1;//隱式轉換,不是賦值,是初始化 //如果希望大家不要寫這樣容易產生歧義的語句,那么用explicit修飾構造函數來 禁止通過構造函數進行隱式轉換,也就是說:對應構造函數有explicit修飾,這句話就是錯的。 MyString str2(10);//隱式調用MyString str1="abcd"; }七、類的對象數組
對象數組:本質是數組,數組的每個元素是對象。
- 如果對象數組不初始化,每個元素都會自動調用無參構造和析構函數;
- 如果對象數組初始化,必須 顯式使用 有參構造 ,逐個元素初始化;
- 棧,先創建的元素后釋放
?
?八、動態對象創建
1. c創建動態對象
當創建一個C++對象時,會發生兩件事:
(1)為對象分配內存
(2)調用構造函數來初始化那塊內存。
C的標準庫提供了malloc以及它的變種calloc和realloc(alloc是allocate的縮寫,表示分配)、釋放內存的Free。
但是
(1)malloc只開辟空間,編譯器不會自動調用構造函數初始化;free只回收空間,還得手動清理對象。
(2)必須確定對象長度。
(3)malloc返回一個void的指針,C++不允許將void指針賦值給其他任何指針,必須強轉。
(4)malloc可能申請內存失敗,所以必須判斷返回值來確保內存分配成功。
所以c++中用 new 和 delete
?2. c++創建動態對象
Person* person=new Person;
new?里面帶有內置的長度計算、類型轉換和安全檢查,并自動調用構造函數完成初始化。
這樣在 堆 創建一個對象,和在 棧 創建一個對象一樣簡單。
delete 先調用析構,然后釋放內存。
*注意:在棧里定義對象數組 與 結構體數組 區分
Student arr[2]={{100,"lucy"},{20,"bob"}};
九、靜態成員
1.靜態成員變量?
用 static 修飾的成員(包括成員變量和成員函數)稱為靜態成員。
- 不管這個類創建了多少對象,靜態成員只有一個拷貝,這個拷貝被所有屬于這個類的對象共享。
- 靜態成員變量(/成員函數)?屬于類,而不是對象(所有對象 共享 一份靜 態成員數據)
- static修飾的成員 定義類的時候必須分配空間。
【正常成員變量是在實例化對象的時候才分配空間,但是static是在定義類的時候就已分配空間。因為所有對象共用一份靜態成員數據,靜態成員要先于對象定義(開辟空間),所有對象才好使用靜態成員數據】
- static修飾的靜態成員數據必須 類中聲明,類外初始化(類外初始化不用加static)。
【
高級別的(比如C++11)支持類中初始化,但是我們不建議 任何成員變量 在類中初始化。
如果靜態成員在 類內初始化 的話,實例化對象時 會出現同一空間被 重復初始化 的問題。
C++11之前,能在類中初始化的成員只有一種,那就是 靜態常量成員。
static const int 可以 類內初始化
static const? ? ? 必須 類內初始化
?】
- 靜態成員數據 可通過類名稱直接訪問
(如果用? 類名稱::變量名? 直接訪問,一定是靜態成員)
【在 定義完類 但沒有實例化對象的時候 想要訪問靜態成員數據怎么辦?可以直接類名稱訪問】
?2.靜態成員函數?
- 靜態成員函數 屬于類 而不是對象,所有對象共享。
- 靜態成員函數? 可以直接通過 類名稱 訪問。
【如圖,如果想訪問 私有靜態成員變量,需要通過公有成員方法(函數),但如果是普通的公有成員方法,需要先實例化對象,通過對象去調用該成員函數。
但如果我們沒有定義對象卻想要訪問靜態成員變量該怎么辦呢?
于是我們可以定義一個靜態成員方法,靜態成員方法屬于類而不是對象,可以直接通過類名稱調用】?
- 靜態成員函數 只能操作 靜態成員變量。
3.單例模式設計?
一種常用的軟件設計模式。
單例模式可以保證系統中 一個類只能實例化一個對象 。
要達到這個目的,我們需要考慮2個問題:
第一,怎么讓其他對象無法用這個類?第二,怎么讓某個對象可以用這個類?
第一:設計私有的構造函數。防止該類在外界實例化對象。
第二:在類中定義一個 static修飾的?靜態指針變量 保存唯一實例的地址,在類外初始化。 并用const修飾為常類型,使其不可更改(只是指針指向的地址不能變,但是指針指向的內容可變);
? ? ? ? ? ?定義一個 靜態成員函數 獲取唯一實例的地址。
【因為外界無法實例化對象,所以該唯一實例只能在類內定義但是如果在類內定義,類還不完整,無法知道這個對象應該開辟多少空間,會報錯。
所以在類內定義一個指針變量,保存唯一實例的地址,在類外初始化該對象。
?】
?
靜態:
- 定義時就開辟了空間
- 所有對象共享這一空間
- 類內定義,類外初始化,初始化時不用加static
- 屬于類,而不是對象
- 可以用? 類名稱::變量名? 直接訪問
- 靜態成員函數 只能操作 靜態成員變量
?十、c++面向對象模型
?1.成員變量 和 函數的存儲
C++成員變量和成員函數是分開存儲的。
非靜態成員變量 內含 在 各自類對象 中;成員函數和靜態成員則?共享,每一個非內聯成員函數只會誕生一份函數實例。
sizeof(類名稱)只是 非靜態成員變量 所占的空間
?2.this指針
?2.1 this指針工作原理
由1我們知道 成員函數是共享的。那如何區分是哪個對象在調用函數呢??
c++用特殊的對象指針 this指針 解決上述問題。this指針指向 被調用的成員函數所屬的對象。
系統默認 this指針 指向對象
注意:靜態成員函數內部沒有this指針
2.2 this指針的應用
- 函數形參和成員同名 可以用this指針。
- ?完成鏈式操作
?2.3 const修飾成員函數
?用const修飾成員函數時,const修飾this指針指向的內存區域,成員函數體內不可以修改本類中任何普通成員變量,當成員變量類型符前 用 mutable 修飾時例外。
十一、友元
友元函數:允許 私有成員被類外訪問 的函數
- 用friend關鍵字聲明,friend只出現在聲明處;
- 一個函數或類 作為另一個類的友元,那么這個函數或類 可以直接訪問另一個類的私有數據。
- 友元重要用在運算符重載上。
1.普通全局函數 作為 類的友元
??
2.類的某個成員函數 作為另一個類的友元
書寫步驟:
(1)向前聲明 另一個類
(2)寫包含友元成員函數的類,其成員函數需?類中聲明 類外實現。?
(3)寫另一個類
【原因:
(1)如果不 向前聲明,goodGay中的Room編譯器找不到
(2)如果不類外實現,比如說visiting01函數,它包含settingRoom,編譯器找不到settingRome
(3)如果把另一個類放在goodGay前面,另一個類中的友元聲明用到了visiting 02,編譯器找不到visiting02,就算 goodGay向前聲明 也沒用?】
?
?3.友員注意事項
(1)不能被繼承(你爹的朋友不一定是你的朋友)
(2)單向(類A是類B的朋友,但類B不一定是類A的朋友)
(3)不具有傳遞性(類B是類A的朋友類C是類B的朋友,但類C不一定是類A的朋友)
說白了就是 某個函數是某個類的友元,那就只有這個函數能訪問這個類的私有成員。?
4.友員案例
4.1電視+遙控器?
#include<iostream> using namespace std;class TV; //遙控器的類作為TV的友元 class Remote { private:TV* p; public:Remote(TV* p);void offOrOn(void);void upVolume(void);void downVolume(void);void upChannel(void);void downChannel(void);void showTv(void);void setChannel(int channel); }; class TV {friend class Remote;enum { OFF, ON };enum { minVol, maxVol = 10 };enum { minChan, maxChan=25 }; private:int state;int volume;int channel; public:TV(){state = OFF;volume = minVol;channel = minChan;}void offOrOn(void);void upVolume(void);void downVolume(void);void upChannel(void);void downChannel(void);void showTv(void); }; int main(int argc, char* argv[]) {TV tv;Remote re(&tv);re.offOrOn();re.upVolume();re.downVolume();re.setChannel(10);re.showTv();/*tv.offOrOn();tv.upVolume();tv.downVolume();tv.upChannel();tv.downChannel();tv.showTv();*/return 0; } void TV::offOrOn() {state = (state == OFF ? ON : OFF); } void TV::upVolume() {if (volume == maxVol){cout << "音量已經最大" << endl;return;}volume++; } void TV::downVolume() {if (volume == minVol){cout << "音量已經最小" << endl;return;}volume--; } void TV::upChannel() {if (channel == maxChan){cout << "頻道已經最大" << endl;return;}volume++; } void TV::downChannel() {if (channel == minVol){cout << "頻道已經最小" << endl;return;}channel--; } void TV::showTv() {cout << "當前電視機狀態:" << (state == OFF ? "關" : "開") << endl;cout << "當前電視機音量:" << volume << endl;cout << "當前電視機頻道:" << channel << endl; }Remote::Remote(TV* p) {this->p = p; }void Remote::offOrOn(void) {//this->offOrOn 錯誤,this指向遙控器對象,但這些操作實際由電視機完成,應該用指向電視機的指針pp->offOrOn(); }void Remote::upVolume(void) {p->upVolume(); }void Remote::downVolume(void) {p->downVolume(); }void Remote::upChannel(void) {p->upChannel(); }void Remote::downChannel(void) {p->downChannel(); }void Remote::showTv(void) {p->showTv(); }void Remote::setChannel(int channel) {if ((channel >= TV::minChan) &&( channel <= TV::maxChan)){p->channel = channel;}else{cout << "頻道"<<channel<<"不在有效范圍內" << endl;} }4.2動態數組類?
//動態數組類.hclass Array { private:int* arr;//存放數組首元素地址int size;//大小,實際存放元素的個數int capacity;//容量 public:Array();Array(int capacity);Array(const Array& b);~Array();int getCapacity(void);int getSize(void);void printArray(void);//尾部插入數據void pushBack(int elem);//尾部刪除元素void popBack(void);//查看某個元素int& at(int pos); }; //動態數組類.cpp#include "動態數組類.h" #include<string.h> #include<iostream> using namespace std;Array::Array() {capacity = 5;size = 0;arr = new int[capacity];//空間清零memset(arr, 0, sizeof(int)*capacity); }Array::Array(int capacity) {this->capacity = capacity;size = 0;arr = new int[capacity];//空間清零memset(arr, 0, sizeof(int) * capacity); }Array::Array(const Array& ob) {capacity = ob.capacity;size = ob.size;//深拷貝arr = new int[capacity];memcpy(arr, ob.arr, sizeof(int) * capacity); } Array::~Array() {if (arr != NULL){delete[]arr;arr = NULL;} } int Array::getCapacity(void) {return capacity; } int Array::getSize(void) {return size; } void Array::printArray(void) {int i = 0;for (i = 0; i < size; i++){cout << arr[i] << " ";}cout << endl; } void Array::pushBack(int elem) {//判斷容器是否滿if (size == capacity){//申請空間int* tmp = new int[2 * capacity];memset(tmp, 0, sizeof(int) * 2 * capacity);//將舊空間內容拷貝到新空間memcpy(tmp, arr, sizeof(int) * size);//釋放舊空間delete[]arr;//讓arr指向新空間arr = tmp;//更新容量capacity = 2 * capacity; }arr[size] = elem;size++; } void Array::popBack(void) {if (size == 0)cout << "容器為空" << endl;else{size--;arr[size] = 0;} } int& Array::at(int pos) {if (pos < 0 || pos >= size){cout << "訪問位置無效" << endl;exit(-1);}return arr[pos];// TODO: 在此處插入 return 語句 } //動態數組類 main.cpp#include<iostream> #include"動態數組類.h" using namespace std;int main(int argc, char* argv[]) {Array ob;cout << "容量:" << ob.getCapacity() << ",大小:" << ob.getSize() << endl;ob.pushBack(10);ob.pushBack(20);ob.pushBack(30);ob.pushBack(40);ob.printArray();cout << "容量:" << ob.getCapacity() << ",大小:" << ob.getSize() << endl;ob.pushBack(50);ob.pushBack(60);ob.printArray();cout << "容量:" << ob.getCapacity() << ",大小:" << ob.getSize() << endl;ob.popBack();ob.popBack();ob.printArray();cout << "容量:" << ob.getCapacity() << ",大小:" << ob.getSize() << endl;cout << "arr[2]=" << ob.at(2) << endl;ob.at(2) = 100;ob.printArray();return 0; }十二、運算符重載
1.基本概念
內涵:對已有的運算符重新定義,賦予其另一種功能,以適應不同的數據類型。
語法:operator運算符
注意:
(1)運算符運算對象的個數 決定了 重載函數的參數個數。
(2)識別運算符左邊的運算對象 是類的對象 還是其他
類的對象:全局函數實現(不推薦)成員函數實現(推薦,少一個參數,還不用設置函數為友元)
其他:只能用全局函數實現
全局函數實現:operator+(ob1,ob2){} 【 ob1/ob2為對象,如果要訪問私有成員,還得設置該函數為友元】
成員函數實現:operator+(ob2){this->...}
2.可以重載的運算符
- size of 、new 、delete既是關鍵字,又是運算符
- 短路特性:比如 a&&b ,左邊為假,整個為假,不會再判斷右邊。那就導致重載時傳參存在問題。雖然可以,但是盡量不要重載它們。
3.重載 輸出運算符?
?*注:
- 此處 全局函數重載實現,記得設置友元
- 前面是編譯器的優化寫法,此處是對 << 的重載。
運算符重載 實際上就是一個 重載函數,調用時可以不用正常的函數調用寫法,可以直接 左對象 運算符 右對象 的形式。ostream是輸出類型
- lucy后不能再加<<endl?
因為重載的<<返回值類型是void,沒有void<<endl這樣的<<定義。
如果要實現可加<<endl等的鏈式操作。可以將返回值改成 輸出類型引用。
4.重載 輸入運算符?
5.重載 加法運算符?
5.1 成員函數實現
lucy+bob 調用相當于 lucy.operator+(bob)
?
5.2 全局函數實現
- 加法不應該修改Lucy和Bob的值,所以需要一個tmp對象去保存 Lucy和bob加后的name、score等值。
- 不能對局部變量引用,返回類型為tmp的值。
6.重載 相等運算符?
7.重載 加加減減 運算符?
a++和++a 對于相同的運算符++功能不一樣,必須重載。
但運算符名一樣(函數名一樣)、參數一樣,怎么重載?
所以用上 占位參數 區分 前置和后置++
++a 調用operator++(a)
a++ 調用operator++(a,int)
成員函數實現重載后置++:
?
?成員函數實現重載前置++:
8.重載 函數調用運算符
重載()運算符 一般用于 為算法提供策略。
?9.智能指針(指針運算符(*、->)重載)
智能指針:解決 堆區空間的對象 釋放問題(自動釋放指針空間,而不需要手動delete)
四個智能指針: auto_ptr,? shared_ptr,? weak_ptr,? unique_ptr 其中后三個是c++11支持,并且第一個已經被c++11棄用。
智能指針?是一個類,用來存儲指針(指向動態分配對象的指針)
? ? ? ?當我們寫一個new語句時,一般就會立即把delete語句直接也寫了,但是我們不能避免程序還未執行到delete時就跳轉了或者在函數中沒有執行到最后的delete語句就返回了,如果我們不在每一個可能跳轉或者返回的語句前釋放資源,就會造成內存泄露。.使用智能指針可以很大程度上的避免這個問題,因為智能指針就是一個類,當超出了類的作用域是,類會自動調用析構函數釋放資源,不用再手動delete指針空間了。
結論:
運算符前后是對象,該運算符重載 且 優化(優化是指 該處實際上是 對象 調用 重載函數 的縮寫)
eg:sp->func();?
//->前是對象,->被重載,該語句為優化,實際上是sp.operator->()->func();
總結
- 上一篇: 交叉熵的物理意义及简单公式推导
- 下一篇: 在 HBuilderX 中使用 tail