C++類與對象深入之運算符重載與const及初始化列表詳解_第1頁
C++類與對象深入之運算符重載與const及初始化列表詳解_第2頁
C++類與對象深入之運算符重載與const及初始化列表詳解_第3頁
C++類與對象深入之運算符重載與const及初始化列表詳解_第4頁
C++類與對象深入之運算符重載與const及初始化列表詳解_第5頁
已閱讀5頁,還剩18頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

第C++類與對象深入之運算符重載與const及初始化列表詳解目錄一:運算符重載相等運算符重載賦值運算符重載小于運算符重載二:const成員const修飾類的成員函數(shù)三:cin、cout重載四:初始化列表構(gòu)造函數(shù)賦初值初始化列表explicit關(guān)鍵字

一:運算符重載

C++為了增強代碼的可讀性引入了運算符的重載,運算符重載是具有特殊函數(shù)名的函數(shù),也具有其返回值類型以及參數(shù)列表,其返回值類型與參數(shù)列表與普通函數(shù)類似。

函數(shù)名字為:關(guān)鍵字operator后面接需要重載的運算符符號

函數(shù)原型:返回值類型operator操作符(參數(shù)列表)

相等運算符重載

對內(nèi)置類型我們想要判斷兩個變量是否相等我們可以直接使用相等運算符,但是如果是一個自定義類型呢?那么這時候就需要重載運算符了。

下面重載一個全局的operator==:

classDate

public:

//默認生成的析構(gòu)函數(shù),內(nèi)置類型成員不做處理,自定義類型成員會去調(diào)用它的析構(gòu)函數(shù)

Date(intyear=1,intmonth=1,intday=1)

_year=year;

_month=month;

_day=day;

voidPrint(){

cout_year"-"_month"-"_dayendl;

intGetYear(){

return_year;

intGetMonth(){

return_month;

intGetDay(){

return_day;

private:

int_year;

int_month;

int_day;

booloperator==(Dated1,Dated2)

returnd1.GetYear()==d2.GetYear()

d1.GetMonth()==d2.GetMonth()

d1.GetDay()==d2.GetDay();

intmain(){

Dated1(2025,5,16);

Dated2(2025,5,16);

if(operator==(d1,d2)){

cout"=="endl;

if(d1==d2){//編譯器會處理成對應重載運算符調(diào)用if(operator==(d1,d2)){

cout"=="endl;

system("pause");

return0;

}

我們把運算符重載成全局的時候,面對私有成員不可類外訪問,我們提供三個函數(shù)接口,當然還有別的處理方式。我們可以上述運算符重載可以判斷兩個自定義日期類是否相等

我們看到主函數(shù)中兩處調(diào)用重載運算符,兩種寫法都可以,第二種方法更簡單,編譯器會自動處理成第一種方式。

我們還可以重載成類的成員函數(shù),作為類成員重載函數(shù)時,其形參看起來比操作數(shù)目少1個

classDate

public:

//默認生成的析構(gòu)函數(shù),內(nèi)置類型成員不做處理,自定義類型成員會去調(diào)用它的析構(gòu)函數(shù)

Date(intyear=1,intmonth=1,intday=1){

_year=year;

_month=month;

_day=day;

voidPrint(){

cout_year"-"_month"-"_dayendl;

booloperator==(constDated)

return_year==d._year

_month==d._month

_day==d._day;

private:

int_year;

int_month;

int_day;

intmain()

Dated1(2025,5,16);

Dated2(2025,5,16);

if(d1.operator==(d2)){

cout"=="endl;

if(d1==d2){//編譯器會處理成對應重載運算符調(diào)用if(d1.operator==(d2))

cout"=="endl;

system("pause");

return0;

}

解釋:重載成成員函數(shù)的時候,成員函數(shù)里隱藏了this指針,形參列表其實是(Date*this,constDated2),函數(shù)調(diào)用時左操作數(shù)是this指針指向的對象!

同樣地,我們看到主函數(shù)中兩處調(diào)用重載運算符,兩種寫法都可以,第二種方法更簡單,編譯器會自動處理成第一種方式。

賦值運算符重載

C++編譯器至少給一個類添加4個函數(shù):

默認構(gòu)造函數(shù)(無參,函數(shù)體為空)默認析構(gòu)函數(shù)(無參,函數(shù)體為空)默認拷貝構(gòu)造函數(shù),對屬性進行值拷貝賦值運算符operator=,對屬性進行值拷貝

賦值運算符主要有4點:

參數(shù)類型返回值檢查是否自己給自己賦值返回*this

代碼示例:

classDate

public:

//默認生成的析構(gòu)函數(shù),內(nèi)置類型成員不做處理,自定義類型成員會去調(diào)用它的析構(gòu)函數(shù)

Date(intyear=1,intmonth=1,intday=1){

_year=year;

_month=month;

_day=day;

voidPrint(){

cout_year"-"_month"-"_dayendl;

//d2=d1;-d2.operator=(d2,d1)

//d1=d1

Dateoperator=(constDated)

if(this!=d)

_year=d._year;

_month=d._month;

_day=d._day;

return*this;

private:

int_year;

int_month;

int_day;

intmain()

Dated1(2025,5,16);

Dated2;

Dated3(d1);//拷貝構(gòu)造--一個存在的對象去初始化另一個要創(chuàng)建的對象

d2=d1;//賦值重載/復制拷貝--兩個已經(jīng)存在對象之間賦值

d1=d1;

system("pause");

return0;

}

解釋:類對象d1給d2賦值,特別注意賦值重載函數(shù)的返回值,和檢查是否自己給自己賦值!

我們要區(qū)分拷貝構(gòu)造和賦值重載:拷貝構(gòu)造是一個存在的對象去初始化另一個要創(chuàng)建的對象,而賦值重載是兩個已經(jīng)存在對象之間賦值。

如下列監(jiān)視列表我們可以看出,結(jié)果d1.d2,d3都是一樣的。

正如一開始所說的,如果一個類中沒有顯示定義賦值運算符重載,編譯器也會生成一個,完成對象的淺拷貝。既然是淺拷貝就有局限,如果類中有屬性指向堆區(qū),做賦值操作時也會出現(xiàn)深淺拷貝問題。

小于運算符重載

下面我們比較日期類的大小:

代碼示例:

classDate

public:

//默認生成的析構(gòu)函數(shù),內(nèi)置類型成員不做處理,自定義類型成員會去調(diào)用它的析構(gòu)函數(shù)

Date(intyear=1,intmonth=1,intday=1){

_year=year;

_month=month;

_day=day;

voidPrint(){

cout_year"-"_month"-"_dayendl;

booloperator(constDated){

if((_yeard._year)

||(_year==d._year_monthd._month)

||(_year==d._year_month==d._monthd._dayd._day))

returntrue;

else{

returnfalse;

private:

int_year;

int_month;

int_day;

intmain()

Dated1(2025,4,16);

Dated2(2025,5,16);

if(d1d2){//編譯器會處理成對應重載運算符調(diào)用if(d1.operator(d2))

cout""endl;

system("pause");

return0;

請按任意鍵繼續(xù)...

二:const成員

const修飾類的成員函數(shù)

將const修飾的類成員函數(shù)稱之為const成員函數(shù),const修飾類成員函數(shù),實際修飾該成員函數(shù)隱含的this指針,表明在該成員函數(shù)中不能對類的任何成員進行修改。

//this指針的本質(zhì)是一個指針常量,指針的指向不可修改

//如果想讓指針指向的值也不可以修改,需要聲明常函數(shù)

我們見下面一段代碼:

voidFunc(constDated)

d.Print();//d.Print(-constDate*

//傳的是一個指針指向的內(nèi)容不可以改變的指針,

//而單純的this指針是指向不可以改變,所以權(quán)限放大了必須在Print函數(shù)后加const,把this指針權(quán)限進一步放小

coutdendl;

voidTestDate3()

Dated1(2025,5,18);

d1.Print();//d1.Print(d1);-Date*

Func(d1);

coutd1endl;

}

代碼解釋:如果Print不是常函數(shù),那么在TestDate3()函數(shù)中調(diào)用Print函數(shù)不會報錯,但是如果在Func函數(shù)中調(diào)用就會報錯,這是因為在TestDate3()函數(shù)中調(diào)用Print函數(shù)傳過去d1的地址,用this指針接收,權(quán)限縮小。而在Func函數(shù)中,d指針指向的內(nèi)容不可以改變,而在形參this指向的內(nèi)容可以改變,所以權(quán)限放大。所以必須給Print函數(shù)加上const,以表示常函數(shù)。

????????????建議:

建議成員函數(shù)中不修改成員變量的成員函數(shù),都可以加上const,普通對象和const對象都可以調(diào)用。

三:cin、cout重載

我們都知道了cin、cout對于內(nèi)置類型可以自動識別其類型進行輸入輸出,這是因為在庫函數(shù)中提供了對應的重載!

下面我們直接看代碼:

classDate

public:

//友元函數(shù)

friendstd::ostreamoperator(std::ostreamout,constDated);

friendstd::istreamoperator(std::istreamout,Dated);

//........

}

首先我們定義成全局函數(shù),必須在對應的類中聲明友元,這樣全局函數(shù)才可以訪問類中成員!

std::ostreamoperator(std::ostreamout,constDated)

outd._year"-"d._month"-"d._dayendl;

returnout;

std::istreamoperator(std::istreamin,Dated)

ind._yeard._monthd._day;

returnin;

四:初始化列表

C++提供了初始化列表語法,用來初始化屬性

構(gòu)造函數(shù)賦初值

在創(chuàng)建對象的時候,編譯器通過調(diào)用構(gòu)造函數(shù),給對象中各個成員變量一個合適的初值。

classPerson{

public:

Person(inta,intb,intc){

m_A=a;

m_B=b;

m_C=c;

private:

intm_A;

intm_B;

intm_C;

intmain(){

Personp(1,2,3);

system("pause");

return0;

}

上述代碼我們通過構(gòu)造函數(shù)賦值的方法來初始化。

注意:上述代碼中調(diào)用構(gòu)造函數(shù)后,對象中已經(jīng)有了一個初始值,但是我們不能將之稱為類對象成員的初始化,只能稱為賦值,因為初始化只可以初始化一次,而構(gòu)造函數(shù)體內(nèi)可以賦值多次

初始化列表

classPerson{

public:

//初始化列表方式初始化

Person(inta,intb,intc)

:m_A(a)

,m_B(b)

,m_C(c)

private:

intm_A;

intm_B;

intm_C;

intmain(){

Personp(1,2,3);

system("pause");

return0;

}

初始化列表:以一個冒號開始,以逗號分隔,每部分由成員變量后面跟上一個放在括號里的初始值或者表達式。

注意:

每個成員變量在初始化列表中只能出現(xiàn)一次(即初始化只一次)。

類中包含以下成員,就必須在初始化列表位置進行初始化。

引用成員變量const成員變量自定義類型成員(該類沒有對應的默認構(gòu)造函數(shù))

我們這里先這么理解一下:初始化列表可以認為就是對象的成員變量定義的地方,對于上面的三種成員只能在定義初始化,而其他的內(nèi)置類型變量,/可以在定義時初始化,也可以定義時不初始化,后面再賦值修改。

下面我們直接上代碼:

intvalue=10;

classA

public:

A(intx)

:_x(x)

/*A(intx=0)

:_x(x)

{}*/②

private:

int_x;

classDate

public:

Date(intyear,intn,inta)

:_n(n)

,_ref(value)

,_aa(a)//①:當自定義類型沒提供默認構(gòu)造時,就在想用我們提供的值去初始化的時候,就在這里顯式的去調(diào)用它的構(gòu)造函數(shù)

//如果有對應的默認構(gòu)造,就不用寫這行。不在初始化列表初始化,自動調(diào)用默認構(gòu)造函數(shù)初始化

_year=year;

//如果不在初始化列表初始化,但是我們還想去改變里面變量的值,只能這么玩

//Aaa(a);調(diào)用默認構(gòu)造②

//_aa=aa;//賦值這里使用了默認提供的賦值運算符重載?這種方式麻煩就用下面這種好

private:

int_year;//聲明

constint_n;

int_ref;

A_aa;

intmain()

Dated1(2025,5,20);//對象定義

system("pause");

return0;

}

代碼解釋:上述代碼中,_n、_ref、_aa都是要在初始化列表初始化的變量,見代碼注釋

??????:上面在初始化的時候都比較麻煩,因此我們建議盡量在初始化列表初始化,如下代碼:

intvalue=10;

classA

public:

A(intx)

:_x(x)

private:

int_x;

classDate

public:

Date(intyear,intn,inta)

:_n(n)

,_ref(value)

,_year(year)

,_aa(a)//當自定義類型沒提供默認構(gòu)造時,就在這里顯式的去調(diào)用它的構(gòu)造函數(shù)

//總結(jié):建議盡量在初始化列表初始化

private:

int_year;//聲明

constint_n;

int_ref;

A_aa;

intmain()

Dated1(2025,5,20);//對象定義

system("pause");

return0;

}

正如我們代碼注釋的地方所說,當自定義類型沒提供默認構(gòu)造時,我們又想用我們提供的值去初始化的時候,就需要我們?nèi)ナ謩拥恼{(diào)用它的構(gòu)造函數(shù),,,,,,

初始化結(jié)果如下:

如果有對應的默認構(gòu)造函數(shù),我們也可以不用寫這行。這時候就不在初始化列表初始化,編譯器自動調(diào)用默認構(gòu)造函數(shù)初始化,初始化為隨機值還是確定值要看是什么類型的默認構(gòu)造函數(shù)。

intvalue=10;

classA

public:

A(intx=10)//全缺省默認構(gòu)造

:_x(x)

private:

int_x;

classDate

public:

Date(intyear,intn,inta)

:_n(n)

,_ref(value)

,_year(year)

//,_aa(a)這時候我們在A類中提供了全缺省的默認構(gòu)造函數(shù),就可以不寫這行代碼

private:

int_year;//聲明

constint_n;

int_ref;

A_aa;

intmain()

Dated1(2025,5,20);//對象定義

system("pause");

return0;

}

如上述代碼,我們沒寫,_aa(a)這一行,但我們提供了默認構(gòu)造函數(shù),結(jié)果表明依然可以初始化。

??????????????????????????????????????????????????????????????????:

下面我們再看一個例子:

classStack

public:

Stack(intcapacity=0)

_a=(int*)malloc(sizeof(int)*capacity);

_top=0;

_capacity=capacity;

private:

int*_a;

int_top;

int_capacity;

classMyQueue

public:

MyQueue(intsize=100)

:_size(size)//如果這里什么都沒寫,那么默認初始化列表就表示_st1就調(diào)用_st1的默認構(gòu)造,_st2同理,

//_size如果給了缺省值,就用缺省值初始化,沒給就是隨機值,

//如果顯式(intsize=1)、_size(size)寫了就用顯式的這個值初始化

private:

Stack_st1;

Stack_st2;

size_t_size=1000;//缺省值如果上面哪個地方給了缺省參數(shù),這里的這個缺省值也沒用了

intmain()

MyQueuemq;

return0;

}

代碼解釋:在MyQueue類中聲明_size的時候給了一個缺省值,然后在默認構(gòu)造函數(shù)的地方也給了缺省形參,還在初始化列表中對_size進行初始化。如下結(jié)果:

classStack

public:

Stack(intcapacity=0)

_a=(int*)malloc(sizeof(int)*capacity);

_top=0;

_capacity=capacity;

private:

int*_a;

int_top;

int_capacity;

classMyQueue

public:

MyQueue(intsize=100)

//:_size(size)//如果這里什么都沒寫,那么默認初始化列表就表示_st1就調(diào)用_st1的默認構(gòu)造,_st2同理,

//_size如果給了缺省值,就用缺省值初始化,沒給就是隨機值,

//如果顯式(intsize=1)、_size(size)寫了就用顯式的這個值初始化

private:

Stack_st1;

Stack_st2;

size_t_size=1000;//缺省值如果上面哪個地方給了缺省參數(shù),這里的這個缺省值也沒用了

intmain()

MyQueuemq;

return0;

}

如果上述_size沒有在初始化列表初始化,那么_size就被聲明時候給的缺省值初始化。如下結(jié)果:

我們再看三段代碼,看看他們的不同之處:

classStack

public:

Stack(intcapacity=0)

_a=(int*)malloc(sizeof(int)*capacity);

_top=0;

_capacity=capacity;

private:

int*_a;

int_top;

int_capacity;

classMyQueue

public:

MyQueue(intsize=100)

:_size(size)

private:

Stack_st1;

Stack_st2;

size_t_size=1000;

intmain()

MyQueuemq(10);

return0;

}

classStack

public:

Stack(intcapacity=0)

_a=(int*)malloc(sizeof(int)*capacity);

_top=0;

_capacity=capacity;

private:

int*_a;

int_top;

int_capacity;

classMyQueue

public:

MyQueue(intsize)

:_size(size)

private:

Stack_st1;

Stack_st2;

size_t_size=1000;

intmain()

MyQueuemq(10);

return0;

}

classStack

public:

Stack(intcapacity=0)

_a=(int*)malloc(sizeof(int)*capacity);

_top=0;

_capacity=capacity;

private:

int*_a;

int_top;

int_capacity;

classMyQueue

public:

MyQueue(intsize=100)

private:

Stack_st1;

Stack_st2;

size_t_size=1000;

intmain()

MyQueuemq(10);

return0;

}

explicit關(guān)鍵字

構(gòu)造函數(shù)不僅可以構(gòu)造和初始化對象,對于單個參數(shù)的構(gòu)造函數(shù),還具有類型轉(zhuǎn)換的作用。

下面我們還是看一段代碼:

classDate

public:

/*explicitDate(intyear)

:_year(year)

cout"Dat

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論