如果一個類中沒有任何成員,那么我們把它稱為空類??疹愔幸矔詣由?個默認(rèn)成員函數(shù)。
默認(rèn)成員函數(shù):用戶沒有顯式實現(xiàn),編譯器會生成的成員函數(shù)稱為默認(rèn)成員函數(shù)。
接下來我們詳細(xì)介紹一下這幾個默認(rèn)成員函數(shù)
2. 構(gòu)造函數(shù) 2.1概念與特征在C語言實現(xiàn)的數(shù)據(jù)結(jié)構(gòu)中,下面以棧(Stack)為例,我們實現(xiàn)過StackInit這個接口,用于對棧進(jìn)行初始化,但是我們在使用棧的時候會經(jīng)常忘記調(diào)用這個函數(shù)對棧初始化,C++為了解決這個問題,就創(chuàng)建了一個叫做構(gòu)造函數(shù)的默認(rèn)成員函數(shù),用來對類進(jìn)行初始化。而且它會在類實例化的時候自動調(diào)用,這就完美解決了我們忘記調(diào)用的問題。
這里需要注意的是,構(gòu)造函數(shù)雖然名稱叫構(gòu)造,但是構(gòu)造函數(shù)的主要任務(wù)并不是開空間創(chuàng)建對象,而是初始化對象。
其特征如下:
2.2特征分析
函數(shù)名與類名相同。
無返回值。
對象實例化時編譯器自動調(diào)用對應(yīng)的構(gòu)造函數(shù)。
構(gòu)造函數(shù)可以重載和缺省參數(shù)。
如果類中沒有顯式定義構(gòu)造函數(shù),則C++編譯器會自動生成一個無參的默認(rèn)構(gòu)造函數(shù),一旦用戶顯式定義編譯器將不再生成。
編譯器自動生成的構(gòu)造函數(shù)對于內(nèi)置類型不做任何處理,對于自定義類型調(diào)用其默認(rèn)構(gòu)造函數(shù)。
無參的構(gòu)造函數(shù)、全缺省的構(gòu)造函數(shù)和編譯器默認(rèn)生成的構(gòu)造函數(shù)都稱為默認(rèn)構(gòu)造函數(shù),并且默認(rèn)構(gòu)造函數(shù)只能有1個。
總結(jié):不傳參數(shù)就可以調(diào)用的構(gòu)造函數(shù),就叫默認(rèn)構(gòu)造函數(shù)
下面我們以Date類為例:
class Date
{public:
Date(int year = 1970, int month = 1, int day = 1)//構(gòu)造函數(shù)
{_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();
return 0;
}
在定義構(gòu)造函數(shù)的時候,函數(shù)名與類名相同(特征1),并且沒有返回值(特征2),上述代碼運行的結(jié)果如下:
顯然我們并沒有初始化d1,但是輸出的d1結(jié)果是已經(jīng)被初始化完成的,所以在實例化d1的時候就已經(jīng)自動調(diào)用了構(gòu)造函數(shù)。(特征3)
class Date
{public:
Date(int year, int month = 1, int day = 1)//構(gòu)造函數(shù)
{_year = year;
_month = month;
_day = day;
}
Date()//構(gòu)造函數(shù)重載
{_year = 1970;
_month = 1;
_day = 1;
}
void Print()
{cout<< _year<< '/'<< _month<< '/'<< _day<< endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{Date d1;
Date d2(2022);
d1.Print();
d2.Print();
return 0;
}
在上述代碼構(gòu)造函數(shù)的參數(shù)中可以看到我們給出了缺省值,調(diào)用的時候程序可以正常運行,可見構(gòu)造函數(shù)可以給出缺省值,并且兩個構(gòu)造函數(shù)無參和帶參構(gòu)成函數(shù)重載(特征4)
這里注意一下,無參和帶參全缺省的構(gòu)造函數(shù)不能同時出現(xiàn),雖然語法上沒有問題,但是在調(diào)用的時候會產(chǎn)生二義性,出現(xiàn)調(diào)用不明確的問題。
在類中如果需要自己實現(xiàn)構(gòu)造函數(shù)的話,一般推薦實現(xiàn)一個全缺省的構(gòu)造函數(shù)即可,防止出現(xiàn)冗余
按照上述的特性5,如果在類中我們沒有實現(xiàn)構(gòu)造函數(shù),那么編譯器會自動給我們生成一個無參的構(gòu)造函數(shù),但是上圖中可以看到,似乎編譯器自動生成的構(gòu)造函數(shù)并沒有什么用,原因在特性6已經(jīng)說明:編譯器自動生成的構(gòu)造函數(shù)并不能對內(nèi)置類型進(jìn)行操作,對于自定義的類型,會調(diào)用它的默認(rèn)構(gòu)造函數(shù)。
注意:在C++11中針對內(nèi)置類型成員不初始化的缺陷,又打了補丁,即:內(nèi)置類型成員變量在類中聲明時可以給默認(rèn)值
無參構(gòu)造函數(shù)、全缺省構(gòu)造函數(shù)、我們沒寫編譯器默認(rèn)生成的構(gòu)造函數(shù),都可以認(rèn)為是默認(rèn)構(gòu)造函數(shù),由于默認(rèn)構(gòu)造函數(shù)時無參的,所以如果出現(xiàn)多于一個的情況,那么調(diào)用的時候就會出現(xiàn)二義性,因此,只能存在一個默認(rèn)構(gòu)造函數(shù)**(特性7)**。
3.析構(gòu)函數(shù) 3.1概念與特征上面我們介紹了構(gòu)造函數(shù),它是對標(biāo)C語言實現(xiàn)的棧中的StackInit,析構(gòu)函數(shù)對標(biāo)的就是StackDestory。那么相對應(yīng)的,析構(gòu)函數(shù)的任務(wù)不是銷毀對象,而是完成對象中的資源清理工作。
析構(gòu)函數(shù)的特征如下:
3.2特征分析
- 析構(gòu)函數(shù)名是在類名前加上字符 ~。
- 無參數(shù)無返回值類型。
- 一個類只能有一個析構(gòu)函數(shù)。若未顯式定義,系統(tǒng)會自動生成默認(rèn)的析構(gòu)函數(shù)。(析構(gòu)函數(shù)不能重載)
- 對象生命周期結(jié)束時,C++編譯器自動調(diào)用析構(gòu)函數(shù)。
- 編譯器生成的默認(rèn)析構(gòu)函數(shù),對自定類型成員調(diào)用它的析構(gòu)函數(shù),對內(nèi)置類型不做操作
- 如果類中沒有申請資源時,析構(gòu)函數(shù)可以不寫,直接使用編譯器生成的默認(rèn)析構(gòu)函數(shù),比如Date類;有資源申請時,一定要寫,否則會造成資源泄漏,比如Stack類。
下面我們以Stack類為例:
class Stack
{public:
Stack(int capacity = 4)
{_a = (int*)malloc(sizeof(int) * capacity);
if (_a == nullptr)
{ perror("malloc fail");
exit(-1);
}
_top = 0;
_capacity = capacity;
}
~Stack()
{free(_a);
_a = nullptr;
_top = _capacity = 0;
}
void Push(int x)
{//...
}
private:
int* _a;
int _top;
int _capacity;
};
在定義析構(gòu)函數(shù)的時候,函數(shù)名函數(shù)名是在類名前加上字符 ~(特征1),并且沒有參數(shù)和返回值(特征2)。
基于上述的Stack類,我們定義一個MyQueue類:
class MyQueue
{public:
void Push(int x)
{_pushST.Push(x);
}
private:
Stack _pushST;
Stack _popST;
};
運行上述代碼,發(fā)現(xiàn)結(jié)果中輸出了構(gòu)造函數(shù)和析構(gòu)函數(shù)的函數(shù)名,證明在代碼運行的過程中自動調(diào)用了構(gòu)造函數(shù)和析構(gòu)函數(shù)(特征4)
運行上述代碼,我們可以看到調(diào)用了兩次Stack的構(gòu)造函數(shù)和析構(gòu)函數(shù),所以對于MyQueue中的Stack的成員,編譯器會自動調(diào)用他的析構(gòu)函數(shù)(特性5)
4.拷貝構(gòu)造函數(shù) 4.1概念與特征在定義內(nèi)置類型的時候,我們有時候會使用類似int a = b
這樣的語句,這就是一種拷貝,對于自定義類型,我們可以直接拷貝,這種拷貝我們把它叫做淺拷貝,還有一種拷貝叫做深拷貝,深拷貝就是創(chuàng)建一個新的對象和數(shù)組,將原對象的各項屬性的“值”(數(shù)組的所有元素)拷貝過來,是“值”而不是“引用”。
我們在實例化一個新的對象的時候,經(jīng)??赡軙龅竭@種我們想拷貝已有對象的數(shù)據(jù),這時候會用到深拷貝,所以引入了拷貝構(gòu)造函數(shù)的概念。
拷貝構(gòu)造函數(shù):只有單個形參,該形參是對本類類型對象的引用(一般常用const修飾),在用已存在的類類型對象創(chuàng)建新對象時由編譯器自動調(diào)用。
拷貝構(gòu)造的特征:
4.2特征分析
拷貝構(gòu)造函數(shù)是構(gòu)造函數(shù)的一個重載形式。
拷貝構(gòu)造函數(shù)的參數(shù)只有一個且必須是類類型對象的引用,使用傳值方式編譯器直接報錯,因為會引發(fā)無窮遞歸調(diào)用。
若未顯式定義,編譯器會生成默認(rèn)的拷貝構(gòu)造函數(shù)。 默認(rèn)的拷貝構(gòu)造函數(shù)對象按內(nèi)存存儲按字節(jié)序完成拷貝,這種拷貝叫做淺拷貝,或者值拷貝。
編譯器自動生成的默認(rèn)拷貝構(gòu)造函數(shù)中,內(nèi)置類型是按照字節(jié)方式直接拷貝的,而自定義類型是調(diào)用其拷貝構(gòu)造函數(shù)完成拷貝的
總結(jié):類中如果沒有涉及資源申請時,拷貝構(gòu)造函數(shù)是否寫都可以;一旦涉及到資源申請時,則拷貝構(gòu)造函數(shù)是一定要寫的,否則就是淺拷貝。
拷貝構(gòu)造函數(shù)典型調(diào)用場景:
使用已存在對象創(chuàng)建新對象
函數(shù)參數(shù)類型為類類型對象
函數(shù)返回值類型為類類型對象
以date類為例
class date
{public:
void print()
{cout<< _year<< '/'<< _month<< '/'<< _day<< endl;
}
date(int year = 1970, int month = 1, int day = 1)
{_year = year;
_month = month;
_day = day;
}
date(const date& d)
{_year = d._year;
_month = d._month;
_day = d._day;
}
private:
int _year;
int _month;
int _day;
};
拷貝構(gòu)造函數(shù)是構(gòu)造函數(shù)的一個重載形式,拷貝構(gòu)造的函數(shù)參數(shù)與構(gòu)造函數(shù)不同**(特性1),由于我們對被拷貝的對象不需要改變它的值,為了安全方面考慮,在參數(shù)列表中加上const。拷貝構(gòu)造的參數(shù)類型是類引用,否則就會引發(fā)無窮遞歸調(diào)用。(特性2)**
在C++中,我們會定義很多個類并且實例化對象,然而我們自定義的這些類對于編譯器是陌生的,所以一些操作符對于自定義的類型無法識別,為了增強代碼的可讀性,C++引入了運算符重載的概念。
運算符重載是具有特殊函數(shù)名的函數(shù),也具有其返回值類型,函數(shù)名字以及參數(shù)列表,其返回值類型與參數(shù)列表與普通的函數(shù)類似。
函數(shù)名為:關(guān)鍵字operator后面接需要重載的運算符符號,例如需要重載+=,那么函數(shù)名就是"operator+=",
函數(shù)原型:**返回值類型 operator操作符(參數(shù)列表) **
注意
不能通過連接其他符號來創(chuàng)建新的操作符:比如operator@
重載操作符必須有一個類類型參數(shù)
用于內(nèi)置類型的運算符,其含義不能改變,例如:內(nèi)置的整型+,不能改變其含義
作為類成員函數(shù)重載時,其形參看起來比操作數(shù)數(shù)目少1,因為成員函數(shù)的第一個參數(shù)為隱藏的this
.*
::
sizeof
?:
.
注意以上5個運算符不能重載。
以重載日期類的日期+天數(shù)為例:
Date類
class Date
{public:
Date(int year = 1970, int month = 1, int day = 1)
{_year = year;
_month = month;
_day = day;
}
//獲取每個月的天數(shù)
int GetMonthDay(int year, int month)
{static int day[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31 };
if ((month == 2) && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))) //閏年
return 29;
return day[month];
}
//打印
void Print()
{cout<< _year<< "/"<< _month<< "/"<< _day<< endl;
}
private:
int _year;
int _month;
int _day;
};
重載:
void operator+=(Date& d, int day)
{d._day += day;
while (d._day >GetMonthDay(d._year, d._month))
{d._day -= GetMonthDay(d._year, d._month);
d._month++;
if (d._month >12)
{ d._month -= 12;
d._year++;
}
}
}
但是,在我們上手去寫的時候就會發(fā)現(xiàn),我們在類外面寫運算符重載的話,不能直接訪問類里面的private成員變量,所以我們推薦把運算符重載寫在類里面,由于類里面的成員函數(shù)的第一個參數(shù)都是隱藏的this指針,所以寫在類里面的運算符重載的參數(shù)通常會比運算符少一個操作數(shù),所以在類里面的日期+天數(shù)重載代碼為:
//運算符重載+=
void operator+=(int day) //只傳遞右操作數(shù),通過this操作左操作數(shù)
{this->_day += day; //這里的this->編譯器會自動添加
while (_day >GetMonthDay(_year, _month))
{_day -= GetMonthDay(_year, _month);
_month++;
if (_month >12)
{_month -= 12;
_year++;
}
}
}
5.2賦值運算符重載賦值重載既是默認(rèn)成員函數(shù),又是運算符重載。
5.2.1特性5.2.2特性分析
- 賦值重載的格式規(guī)范;
- 賦值運算符只能重載成類的成員函數(shù)不能重載成全局函數(shù);
- 若未顯式定義,編譯器會生成默認(rèn)的賦值重載函數(shù);
- 默認(rèn)的賦值重載函數(shù)對內(nèi)置類型以字節(jié)為單位直接進(jìn)行拷貝 – 淺拷貝,對自定義類型調(diào)用其自身的賦值重載函數(shù);
1.函數(shù)格式:
賦值重載函數(shù)的格式一般有如下要求:
使用引用做參數(shù),并以 const 修飾
我們知道,使用傳值傳參時函數(shù)形參是實參的一份臨時拷貝,所以傳值傳參會調(diào)用拷貝構(gòu)造函數(shù);而使用引用做參數(shù)時,形參是實參的別名,從而減少了調(diào)用拷貝構(gòu)造在時間和空間上的消耗;另外,賦值重載只會改變被賦值對象,而不會改變賦值對象,所以我們使用 const 來防止函數(shù)內(nèi)部的誤操作;
void operator=(const Date& d);
使用引用做返回值且返回值為*this
我們可以對內(nèi)置類型進(jìn)行連續(xù)賦值,比如int i,j; i = j = 0;
那么對于自定義類型來說,我們也可以使用運算符重載來讓其支持連續(xù)賦值,則重載函數(shù)就必須具有返回值;同時,由于我們是在函數(shù)外部調(diào)用重載函數(shù),所以重載函數(shù)調(diào)用結(jié)束后該對象仍然存在,那么我們就可以使用引用作為函數(shù)的返回值,從而減少一次返回值的拷貝,提高程序效率;
另外,我們一般使用左操作數(shù)作為函數(shù)的返回值,也就是 this 指針指向的對象;
Date& operator=(const Date& d);
檢測是否自己給自己賦值
用戶在調(diào)用成員函數(shù)時有可能發(fā)生下面這種情況:Date d1; Date& d2 = d1; d1 = d2;
這種情況對于只需要淺拷貝的對象來說并沒有什么大礙,但對于有資源申請,需要進(jìn)行深拷貝的對象來說就會發(fā)生不可控的事情,具體案例我們在后文中講解;
在 《Effective C++》中對賦值重載函數(shù)自我賦值的解釋是這樣的:
2.重載為成員函數(shù):
賦值運算符只能重載成類的成員函數(shù)不能重載成全局函數(shù),這是因為賦值重載函數(shù)作為六個默認(rèn)成員函數(shù)之一,如果我們不顯示實現(xiàn),編譯器會默認(rèn)生成;此時用戶如果再在類外自己實現(xiàn)一個全局的賦值運算符重載,就會和編譯器在類中生成的默認(rèn)賦值運算符重載沖突,從而造成鏈接錯誤。
3.深淺拷貝:
賦值重載函數(shù)的特性和拷貝構(gòu)造函數(shù)非常類似 – 如果我們沒有顯式定義賦值重載,則編譯器會自動生成一個賦值重載,且自動生成的函數(shù)對內(nèi)置類型以字節(jié)為單位直接進(jìn)行拷貝,對自定義類型會去調(diào)用其自身的賦值重載函數(shù);所以對于沒有資源申請的類來說,我們不用自己去寫賦值重載函數(shù),直接使用默認(rèn)生成的即可,因為這種類只需要進(jìn)行淺拷貝 (值拷貝),比如 Date 類;而對于有資源申請的類來說,我們必須自己手動實現(xiàn)賦值重載函數(shù),來完成深拷貝工作;比如 Stack 類;
6.const成員&&取地址及const取地址操作符重載 6.1const成員**注:**拷貝構(gòu)造函數(shù)完成的是初始化工作,在創(chuàng)建對象時自動調(diào)用;賦值重載完成的是已存在的對象之間的拷貝,需要手動調(diào)用;
**總結(jié):**自動生成的賦值重載函數(shù)對成員變量的處理規(guī)則和析構(gòu)函數(shù)一樣 – 對內(nèi)置類型以字節(jié)方式按值拷貝,對自定義類型調(diào)用其自身的賦值重載函數(shù);我們可以理解為:需要寫析構(gòu)函數(shù)的類就需要寫賦值重載函數(shù),不需要寫析構(gòu)函數(shù)的類就不需要寫賦值重載函數(shù);
我們看下面一個例子:
class date
{public:
void print()
{cout<< _year<< '/'<< _month<< '/'<< _day<< endl;
}
date(int year = 1970, int month = 1, int day = 1)
{_year = year;
_month = month;
_day = day;
}
date(const date& d)
{_year = d._year;
_month = d._month;
_day = d._day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{date d1(2022,12,1);
const date d2(d1);
d1.print();
d2.print();
return 0;
}
這段代碼運行會報以下錯誤,原因是我們在調(diào)用d2.print()
的時候默認(rèn)的this指針參數(shù)的了類型是date* const this
,this指向的值是可修改的,但是實際上d2是const修飾的對象,所以會造成權(quán)限的放大。
要解決這類問題的話,我們就需要把this的類型改為const date* const this
,但是this指針是隱藏的,所以C++提供了一種新的方式,就是在函數(shù)參數(shù)的括號后面加const表示修飾*this的const。
void print() const
這兩個默認(rèn)成員函數(shù)一般不用重新定義 ,編譯器默認(rèn)會生成。如果一定要自己定義的話,那么代碼是這樣的:
class date
{public:
date* operator&()
{return this;
}
const date* operator&() const
{return this;
}
private:
int _year;
int _month;
int _day;
};
這兩個運算符一般不需要重載,使用編譯器生成的默認(rèn)取地址的重載即可,只有特殊情況,才需要重載,比如想讓別人獲取到指定的內(nèi)容
7、總結(jié)C++的類里面存在六個默認(rèn)成員函數(shù) – 構(gòu)造、析構(gòu)、拷貝構(gòu)造、賦值重載、取地址重載、const 取地址重載,其中前面四個函數(shù)非常重要,也非常復(fù)雜,需要我們根據(jù)具體情況判斷是否需要顯式定義,而最后兩個函數(shù)通常不需要顯示定義,使用編譯器默認(rèn)生成的即可;
1、構(gòu)造函數(shù)
- 構(gòu)造函數(shù)完成對象的初始化工作,由編譯器在實例化對象時自動調(diào)用;
- 默認(rèn)構(gòu)造函數(shù)是指不需要傳遞參數(shù)的構(gòu)造函數(shù),一共有三種 – 編譯器自動生成的、顯式定義且無參數(shù)的、顯式定義且全缺省的;
如果用戶顯式定義了構(gòu)造函數(shù),那么編譯器會根據(jù)構(gòu)造函數(shù)的內(nèi)容進(jìn)行初始化,如果用戶沒有顯式定義,那么編譯器會調(diào)用默生成的構(gòu)造函數(shù);- 默認(rèn)生成的構(gòu)造函數(shù)對內(nèi)置類型不處理,對自定義類型會去調(diào)用自定義類型的默認(rèn)構(gòu)造;
- 為了彌補構(gòu)造函數(shù)對內(nèi)置類型不處理的缺陷,C++11打了一個補丁 – 允許在成員變量聲明的地方給缺省值;如果構(gòu)造函數(shù)沒有對該變量進(jìn)行初始化,則該變量會被初始化為缺省值;
- 構(gòu)造函數(shù)還存在一個初始化列表,初始化列表的存在有著非常大的意義;
2、析構(gòu)函數(shù)
- 析構(gòu)函數(shù)完成對象中資源的清理工作,由編譯器在銷毀對象時自動調(diào)用;
- 如果用戶顯式定義了析構(gòu)函數(shù),編譯器會根據(jù)析構(gòu)函數(shù)的內(nèi)容進(jìn)行析構(gòu);如果用戶沒有顯示定義,編譯器會調(diào)用默認(rèn)生成的析構(gòu)函數(shù);
- 默認(rèn)生成的析構(gòu)函數(shù)對內(nèi)置類型不處理,對自定義類型會去調(diào)用自定義類型的析構(gòu)函數(shù);
- 如果類中有資源的申請,比如動態(tài)開辟空間、打開文件,那么需要我們顯式定義析構(gòu)函數(shù);
3、拷貝構(gòu)造
- 拷貝構(gòu)造函數(shù)是用一個已存在的對象去初始化另一個正在實例化的對象,由編譯器在實例化對象時自動調(diào)用;
- 拷貝構(gòu)造的參數(shù)必須為引用類型,否則編譯器報錯 – 值傳遞會引發(fā)拷貝構(gòu)造函數(shù)的無窮遞歸;
- 如果用戶顯式定義了拷貝構(gòu)造函數(shù),編譯器會根據(jù)拷貝構(gòu)造函數(shù)的內(nèi)容進(jìn)行拷貝;如果用戶沒有顯示定義,編譯器會調(diào)用默認(rèn)生成的拷貝構(gòu)造函數(shù);
- 默認(rèn)生成的拷貝構(gòu)造函數(shù)對于內(nèi)置類型完成值拷貝 (淺拷貝),對于自定義類型會去調(diào)用自定義類型的拷貝構(gòu)造函數(shù);
- 當(dāng)類里面有空間的動態(tài)開辟時,直接進(jìn)行值拷貝會讓兩個指針指向同一塊動態(tài)內(nèi)存,從而使得對象銷毀時對同一塊空間析構(gòu)兩次;所以這種情況下我們需要自己顯式定義拷貝構(gòu)造函數(shù)完成深拷貝;
4、運算符重載
- 運算符重載是C++為了增強代碼的可讀性而引入的語法,它只能對自定義類型使用,其函數(shù)名為 operator 關(guān)鍵字加相關(guān)運算符;
- 由于運算符重載函數(shù)通常都要訪問類的成員變量,所以我們一般將其定義為類的成員函數(shù);同時,因為類的成員函數(shù)的一個參數(shù)為隱藏的 this 指針,所以其看起來會少一個參數(shù);
- 同一運算符的重載函數(shù)之間也可以構(gòu)成函數(shù)重載,比如 operator++ 與 operator++(int);
5、賦值重載
- 賦值重載函數(shù)是將一個已存在對象中的數(shù)據(jù)賦值給另一個已存在的對象,注意不是初始化,需要自己顯示調(diào)用;它屬于運算符重載的一種;
- 如果用戶顯式定義了賦值重載函數(shù),編譯器會根據(jù)賦值重載函數(shù)的內(nèi)容進(jìn)行賦值;如果用戶沒有顯示定義,編譯器會調(diào)用默認(rèn)生成的賦值重載函數(shù);
- 默認(rèn)生成的賦值重載函數(shù)對于內(nèi)置類型完成值拷貝 (淺拷貝),對于自定義類型會去調(diào)用自定義類型的賦值重載函數(shù);
- 賦值重載函數(shù)和拷貝構(gòu)造函數(shù)一樣,也存在著深淺拷貝的問題,且其與拷貝構(gòu)造函數(shù)不同的地方在于它還很有可能造成內(nèi)存泄漏;所以當(dāng)類中有空間的動態(tài)開辟時我們需要自己顯式定義賦值重載函數(shù)來釋放原空間以及完成深拷貝;
- 為了提高函數(shù)效率與保護(hù)對象,通常使用引用作參數(shù),并加以 const 修飾;同時為了滿足連續(xù)賦值,通常使用引用作返回值,且一般返回左操作數(shù),即 *this;
- 賦值重載函數(shù)必須定義為類的成員函數(shù),否則編譯器默認(rèn)生成的賦值重載會與類外自定義的賦值重載沖突;
6、const 成員函數(shù)
- 由于指針和引用傳遞參數(shù)時存在權(quán)限的擴(kuò)大、縮小與平移的問題,所以 const 類型的對象不能調(diào)用成員函數(shù),因為成員函數(shù)的 this 指針默認(rèn)是非 const 的,二者之間傳參存在權(quán)限擴(kuò)大的問題;
- 同時我們?yōu)榱颂岣吆瘮?shù)效率以及保護(hù)對象,一般都會將成員函數(shù)的第二個參數(shù)使用 const 修飾,這就導(dǎo)致了該對象在成員函數(shù)內(nèi)也不能調(diào)用其他成員函數(shù);
- 為了解決這個問題,C++設(shè)計出了 const 成員函數(shù) – 在函數(shù)最后面添加 const 修飾,該 const 只修飾 this 指針,不修飾函數(shù)的其他參數(shù);
- 所以如果我們在設(shè)計類時,只要成員函數(shù)不改變第一個對象,我們建議最后都使用 const 修飾;
7、取地址重載與 const 取地址重載
- 取地址重載與 const 取地址重載是獲取一個對象/一個只讀對象的地址,需要自己顯式調(diào)用;它們屬于運算符重載,同時它們二者之間還構(gòu)成函數(shù)重載;
- 大多數(shù)情況下我們都不會去顯示實現(xiàn)這兩個函數(shù),使用編譯器默認(rèn)生成的即可;只有極少數(shù)情況需要我們自己定義,比如防止用戶獲取到一個對象的地址;
員函數(shù),否則編譯器默認(rèn)生成的賦值重載會與類外自定義的賦值重載沖突;
6、const 成員函數(shù)
- 由于指針和引用傳遞參數(shù)時存在權(quán)限的擴(kuò)大、縮小與平移的問題,所以 const 類型的對象不能調(diào)用成員函數(shù),因為成員函數(shù)的 this 指針默認(rèn)是非 const 的,二者之間傳參存在權(quán)限擴(kuò)大的問題;
- 同時我們?yōu)榱颂岣吆瘮?shù)效率以及保護(hù)對象,一般都會將成員函數(shù)的第二個參數(shù)使用 const 修飾,這就導(dǎo)致了該對象在成員函數(shù)內(nèi)也不能調(diào)用其他成員函數(shù);
- 為了解決這個問題,C++設(shè)計出了 const 成員函數(shù) – 在函數(shù)最后面添加 const 修飾,該 const 只修飾 this 指針,不修飾函數(shù)的其他參數(shù);
- 所以如果我們在設(shè)計類時,只要成員函數(shù)不改變第一個對象,我們建議最后都使用 const 修飾;
7、取地址重載與 const 取地址重載
- 取地址重載與 const 取地址重載是獲取一個對象/一個只讀對象的地址,需要自己顯式調(diào)用;它們屬于運算符重載,同時它們二者之間還構(gòu)成函數(shù)重載;
- 大多數(shù)情況下我們都不會去顯示實現(xiàn)這兩個函數(shù),使用編譯器默認(rèn)生成的即可;只有極少數(shù)情況需要我們自己定義,比如防止用戶獲取到一個對象的地址;
參考野豬佩奇大佬博客:大佬博客鏈接
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧
網(wǎng)頁標(biāo)題:【C++】類和對象(中)-創(chuàng)新互聯(lián)
當(dāng)前URL:http://chinadenli.net/article48/despep.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)網(wǎng)站制作、靜態(tài)網(wǎng)站、定制網(wǎng)站、服務(wù)器托管、微信公眾號、面包屑導(dǎo)航
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容