一、拷貝構(gòu)造
拷貝構(gòu)造函數(shù)的特征:
1、拷貝構(gòu)造函數(shù)是構(gòu)造函數(shù)的一個(gè)重載形式;
2、拷貝構(gòu)造函數(shù)的參數(shù)只有一個(gè)且必須是同類類型對(duì)象的引用,使用傳值方式編譯器直接報(bào)錯(cuò),因?yàn)闀?huì)引發(fā)無窮遞歸調(diào)用。
在c++中自定義類型傳值傳參的時(shí)候要調(diào)用拷貝構(gòu)造函數(shù)。
3、若未顯式定義,編譯器會(huì)生成默認(rèn)的拷貝構(gòu)造函數(shù)。默認(rèn)的拷貝構(gòu)造函數(shù)對(duì)象按內(nèi)存存儲(chǔ)按字節(jié)序完成拷貝,這種拷貝叫做淺拷貝,或者值拷貝。
默認(rèn)拷貝構(gòu)造對(duì)內(nèi)置類型進(jìn)行值拷貝(淺拷貝),對(duì)自定義類型調(diào)用它的拷貝構(gòu)造。
class Date
{
public:
Date(int year = 1, int month = 1, int day = 1)
:_year(year)
,_month(month)
,_day(day)
{}
//拷貝構(gòu)造
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
void Print()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2023, 7, 27);
Date d2(d1);//拷貝構(gòu)造
d1.Print();
d2.Print();
return 0;
}
運(yùn)行結(jié)果:
對(duì)于上述Date類,拷貝構(gòu)造是直接賦值給另一個(gè)對(duì)象,但是對(duì)于Stack類,如果也是直接賦值拷貝,那么將會(huì)導(dǎo)致問題。
所以:類中如果沒有涉及資源申請(qǐng)時(shí),拷貝構(gòu)造函數(shù)是否寫都可以;一旦涉及到資源申請(qǐng)
時(shí),則拷貝構(gòu)造函數(shù)是一定要寫的,否則就是淺拷貝。
拷貝構(gòu)造函數(shù)調(diào)用場景:
- 使用已存在對(duì)象創(chuàng)建新對(duì)象;
- 函數(shù)參數(shù)類型為類類型對(duì)象;
- 函數(shù)返回值類型為類類型對(duì)象;
二、賦值運(yùn)算符重載
C++為了增強(qiáng)代碼的可讀性引入了運(yùn)算符重載,運(yùn)算符重載是具有特殊函數(shù)名的函數(shù),也具有其
返回值類型,函數(shù)名字以及參數(shù)列表,其返回值類型與參數(shù)列表與普通的函數(shù)類似。
函數(shù)名字為:關(guān)鍵字operator后面接需要重載的運(yùn)算符符號(hào)。
函數(shù)原型:返回值類型 operator操作符(參數(shù)列表)
注意事項(xiàng):
- 不能通過連接其他符號(hào)來創(chuàng)建新的操作符:比如operator@
- 重載操作符必須有一個(gè)類類型參數(shù)
- 用于內(nèi)置類型的運(yùn)算符,其含義不能改變,例如:內(nèi)置的整型+,不 能改變其含義
- 作為類成員函數(shù)重載時(shí),其形參看起來比操作數(shù)數(shù)目少1,因?yàn)槌蓡T函數(shù)的第一個(gè)參數(shù)為隱
藏的this - 這? ? .*? ?sizeof? ? ::? ? ?:? ? .? ? 5個(gè)運(yùn)算符不能重載
- 不能改變操作符的操作數(shù)的個(gè)數(shù)
class Date
{
public:
Date(int year = 1, int month = 1, int day = 1)
:_year(year)
,_month(month)
,_day(day)
{}
void Print()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
Date& operator=(const Date& d)
{
if (this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2023, 7, 27);
Date d3;
d3 = d1;//賦值
d3.Print();
return 0;
}
1、賦值運(yùn)算符重載格式:
- 參數(shù)類型:const T&,傳遞引用可以提高傳參效率
- 返回值類型:T&,返回引用可以提高返回的效率,有返回值目的是為了支持連續(xù)賦值
- 檢測是否自己給自己賦值
- 返回*this :要復(fù)合連續(xù)賦值的含義
2、賦值運(yùn)算符只能重載成類的成員函數(shù)不能重載成全局函數(shù),原因是賦值運(yùn)算符如果不顯式現(xiàn),編譯器會(huì)生成一個(gè)默認(rèn)的。此時(shí)用戶再在類外自己實(shí)現(xiàn)一個(gè)全局的賦值運(yùn)算符重載,就和編譯器在類中生成的默認(rèn)賦值運(yùn)算符重載沖突了,故賦值運(yùn)算符重載只能是類的成員函數(shù)。
3、用戶沒有顯式實(shí)現(xiàn)時(shí),編譯器會(huì)生成一個(gè)默認(rèn)賦值運(yùn)算符重載,以值的方式逐字節(jié)拷貝。注意:內(nèi)置類型成員變量是直接賦值的,而自定義類型成員變量需要調(diào)用對(duì)應(yīng)類的賦值運(yùn)算符重載完成賦值。
注意:如果類中未涉及到資源管理,賦值運(yùn)算符是否實(shí)現(xiàn)都可以;一旦涉及到資源管理則必須要實(shí)現(xiàn)。
?
三、const成員
四、取地址及const取地址操作符重載
//這兩個(gè)默認(rèn)成員函數(shù)一般不用重新定義,編譯器會(huì)自動(dòng)生成
class Date
{
public :
Date* operator&()
{
return this ;
}
const Date* operator&()const
{
return this ;
}
private :
int _year ;
int _month ;
int _day ;
};
五、初始化列表
構(gòu)造函數(shù)初始化兩種方式:1、函數(shù)體內(nèi)賦值 2、初始化列表
初始化列表:以一個(gè)冒號(hào)開始,接著是一個(gè)以逗號(hào)分隔的數(shù)據(jù)成員列表,每個(gè)"成員變量"后面跟
一個(gè)放在括號(hào)中的初始值或表達(dá)式。
?
class Date
{
public:
//初始化列表
Date(int year = 1, int month = 1, int day = 1)
:_year(year)
,_month(month)
,_day(day)
{}
private:
int _year;
int _month;
int _day;
};
注意:
1、每個(gè)成員變量在初始化列表中最多只能出現(xiàn)一次;
2、類中包含引用成員變量、const成員變量、自定義類型成員(且沒有默認(rèn)構(gòu)造函數(shù))時(shí),必須放在初始化列表位置進(jìn)行初始化;
3、盡量使用初始化列表初始化,因?yàn)椴还苣闶欠袷褂贸跏蓟斜?,?duì)于自定義類型成員變量,一定會(huì)先使用初始化列表初始化。
4、成員變量在類中聲明次序就是其在初始化列表中的初始化順序,與其在初始化列表中的先后次序無關(guān)。
六、explicit關(guān)鍵字
?構(gòu)造函數(shù)不僅可以構(gòu)造與初始化對(duì)象,對(duì)于單個(gè)參數(shù)或者除第一個(gè)參數(shù)無默認(rèn)值其余均有默認(rèn)值
的構(gòu)造函數(shù),還具有類型轉(zhuǎn)換的作用。
class A
{
public:
//explicit修飾構(gòu)造函數(shù),將會(huì)禁止構(gòu)造函數(shù)的隱式轉(zhuǎn)換
explicit A(int a)
:_a(a)
{}
private:
int _a;
};
int main()
{
A a2 = 2;//隱式類型轉(zhuǎn)換,整型轉(zhuǎn)換成自定義類型
//2構(gòu)造一個(gè)A的臨時(shí)對(duì)象,臨時(shí)對(duì)象再拷貝構(gòu)造a2 -----> 優(yōu)化成用2直接構(gòu)造
return 0;
}
用explicit修飾構(gòu)造函數(shù),將會(huì)禁止構(gòu)造函數(shù)的隱式轉(zhuǎn)換。
七、static成員
聲明為static的類成員稱為類的靜態(tài)成員,用static修飾的成員變量,稱之為靜態(tài)成員變量;用
static修飾的成員函數(shù),稱之為靜態(tài)成員函數(shù)。靜態(tài)成員變量一定要在類外進(jìn)行初始化。
計(jì)算程序中創(chuàng)建了多少個(gè)對(duì)象:
class A
{
public:
A()
{
++_scount;
}
A(const A& a)
{
++_scount;
}
~A()
{
--_scount;
}
//static修飾的靜態(tài)成員函數(shù),沒有this指針,指定類域和訪問限定符就可以訪問
//靜態(tài)的不需要對(duì)象,突破類域就可以訪問
static int GetACount()
{
return _scount;
}
private:
//靜態(tài)成員變量,屬于類的每個(gè)對(duì)象貢享,存儲(chǔ)在靜態(tài)區(qū)
static int _scount; //聲明
};
//靜態(tài)成員變量,必須再類外初始化
int A::_scount = 0;
int main()
{
cout << A::GetACount() << endl;//0
A aa1;
A aa2;
cout << A::GetACount() << endl;//2
A aa3(aa1);
cout << A::GetACount() << endl;//3
return 0;
}
注意:
1、靜態(tài)成員為所有類對(duì)象所共享,不屬于某個(gè)具體的對(duì)象,存放在靜態(tài)區(qū);
2、靜態(tài)成員變量必須在類外定義,定義時(shí)不添加static關(guān)鍵字,類中只是聲明;
3、類靜態(tài)成員即可用 類名::靜態(tài)成員 或者 對(duì)象.靜態(tài)成員 來訪問;
4、靜態(tài)成員函數(shù)沒有隱藏的this指針,不能訪問任何非靜態(tài)成員;
5、靜態(tài)成員也是類的成員,受public、protected、private 訪問限定符的限制;
八、友元
現(xiàn)在嘗試去重載operator<<,然后發(fā)現(xiàn)沒辦法將operator<<重載成成員函數(shù)。因?yàn)閏out的輸出流對(duì)象和隱含的this指針在搶占第一個(gè)參數(shù)的位置。this指針默認(rèn)是第一個(gè)參數(shù)也就是左操作數(shù)了。但是實(shí)際使用中cout需要是第一個(gè)形參對(duì)象,才能正常使用。所以要將operator<<重載成全局函數(shù)。但又會(huì)導(dǎo)致類外沒辦法訪問成員,此時(shí)就需要友元來解決。operator>>同理。
class Date
{
public:
Date(int year = 1, int month = 1, int day = 1)
:_year(year)
,_month(month)
,_day(day)
{
}
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& in, Date& d);
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& out, const Date& d)
{
out << d._year << "/" << d._month << "/" << d._month << endl;
return out;
}
istream& operator>>(istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
return in;
}
int main()
{
Date d1;
//cout << d1;//流插入重載
cin >> d1;
cout << d1;
return 0;
}
注意:
1、友元函數(shù)可訪問類的私有和保護(hù)成員,但不是類的成員函數(shù)
2、友元函數(shù)不能用const修飾
3、友元函數(shù)可以在類定義的任何地方聲明,不受類訪問限定符限制
4、一個(gè)函數(shù)可以是多個(gè)類的友元函數(shù)
5、友元函數(shù)的調(diào)用與普通函數(shù)的調(diào)用原理相同
九、內(nèi)部類
內(nèi)部類:如果一個(gè)類定義在另一個(gè)類的內(nèi)部,這個(gè)內(nèi)部類就叫做內(nèi)部類。內(nèi)部類是一個(gè)獨(dú)立的類,
它不屬于外部類,更不能通過外部類的對(duì)象去訪問內(nèi)部類的成員。外部類對(duì)內(nèi)部類沒有任何優(yōu)越
的訪問權(quán)限。
注意:內(nèi)部類就是外部類的友元類,參見友元類的定義,內(nèi)部類可以通過外部類的對(duì)象參數(shù)來訪
問外部類中的所有成員。但是外部類不是內(nèi)部類的友元。
特性:
1. 內(nèi)部類可以定義在外部類的public、protected、private都是可以的。
2. 注意內(nèi)部類可以直接訪問外部類中的static成員,不需要外部類的對(duì)象/類名。
3. sizeof(外部類)=外部類,和內(nèi)部類沒有任何關(guān)系
十、匿名對(duì)象
匿名對(duì)象生命周期在當(dāng)前行,即用即銷毀;文章來源:http://www.zghlxwxcb.cn/news/detail-609722.html
const引用可以延長匿名對(duì)象的生命周期;文章來源地址http://www.zghlxwxcb.cn/news/detail-609722.html
到了這里,關(guān)于c++類和對(duì)象(拷貝構(gòu)造、運(yùn)算符重載、初始化列表、靜態(tài)成員、友元等)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!