自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

適合具備 C 語(yǔ)言基礎(chǔ)的 C++ 教程之四

開發(fā) 后端
在接下來(lái)地?cái)⑹鲋校覀儗⒅刂v述運(yùn)算符重載時(shí)地一些更為細(xì)致地內(nèi)容,其中就包括當(dāng)重載地運(yùn)算符返回值為引用和非引用兩種狀態(tài)時(shí),代碼執(zhí)行效率地高低以及采用在類內(nèi)實(shí)現(xiàn)運(yùn)算符重載函數(shù)

[[382304]]

前言

在上一則教程中,我們講述了重載運(yùn)算符中前 ++和后++的重載函數(shù)的實(shí)現(xiàn),闡述了在 C++中可以將運(yùn)算符進(jìn)行重載的方法,這種方法大大地便利了程序員編寫代碼,在接下來(lái)地?cái)⑹鲋?,我們將著重講述運(yùn)算符重載時(shí)地一些更為細(xì)致地內(nèi)容,其中就包括當(dāng)重載地運(yùn)算符返回值為引用和非引用兩種狀態(tài)時(shí),代碼執(zhí)行效率地高低以及采用在類內(nèi)實(shí)現(xiàn)運(yùn)算符重載函數(shù)的方法。

返回值為引用和非引用的區(qū)別

在上述所示的類當(dāng)中,增加一部分代碼,加入析構(gòu)函數(shù)以及拷貝構(gòu)造函數(shù),代碼如下所示:

  1. class Point 
  2. private: 
  3.     int x; 
  4.     int y; 
  5.  
  6. public
  7.     Point()  
  8.     { 
  9.         cout<<"Point()"<<endl; 
  10.     } 
  11.     Point(int x, int y) : x(x), y(y)  
  12.     { 
  13.         cout<<"Point(int x, int y)"<<endl; 
  14.     } 
  15.  
  16.     Point(const Point& p) 
  17.     { 
  18.         cout<<"Point(const Point& p)"<<endl; 
  19.         x = p.x; 
  20.         y = p.y; 
  21.     } 
  22.     ~Point()  
  23.     { 
  24.         cout<<"~Point()"<<endl; 
  25.     } 
  26.  
  27.     friend Point operator++(Point &p); 
  28.     friend Point operator++(Point &p, int a); 
  29.  
  30.     void printInfo() 
  31.     { 
  32.         cout<<"("<<x<<", "<<y<<")"<<endl; 
  33.     } 
  34. }; 

在上述的代碼中,我們?cè)跇?gòu)造函數(shù)以及拷貝構(gòu)造函數(shù)析構(gòu)函數(shù)都加入了打印信息,其中,運(yùn)算符重載函數(shù)前++和后++函數(shù)沿用之前的一樣,返回值不是引用,與此同時(shí),我們?cè)谇? ++和后 ++函數(shù)中也加入打印信息的代碼,代碼如下所示:

  1. /* ++p */ 
  2. Point operator++(Point &p) 
  3.     cout << "++p" << endl; 
  4.     p.x += 1; 
  5.     p.y += 1; 
  6.     return p; 
  7.  
  8. /* p++ */ 
  9. Point operator++(Point &p, int a) 
  10.     cout << "p++" << endl; 
  11.     Point n; 
  12.     n = p; 
  13.     p.x += 1; 
  14.     p.y += 1; 
  15.     return n; 

上述便是前 ++和 后 ++的重載函數(shù),緊接著,書寫主函數(shù)的代碼,觀察當(dāng)返回值為非引用的時(shí)候,代碼的運(yùn)行效果,主函數(shù)代碼如下所示:

  1. int main(int argc, char **argv) 
  2.     Point p1(1, 2); 
  3.  
  4.     cout<<"begin"<<endl; 
  5.     ++p1; 
  6.     cout << "******************"<<endl; 
  7.  
  8.     p1++; 
  9.     cout<<"end"<<endl; 
  10.  
  11.     return 0; 

上述代碼的運(yùn)行結(jié)果如下所示:

lhp7d3H1crAE9u2

依據(jù)運(yùn)行結(jié)果我們分析一下,第一條輸出信息 Point(int x, int y)是因?yàn)閳?zhí)行了 Point p1(1,2);語(yǔ)句而調(diào)用的構(gòu)造函數(shù),++p這條輸出信息同樣也是因?yàn)閳?zhí)行了 ++p;而調(diào)用的構(gòu)造函數(shù),那緊接著的兩條輸出信息是如何產(chǎn)生的呢,我們回過(guò)頭去看看++p的函數(shù),可以看到 ++p的函數(shù)是一個(gè)返回值為 Point類型的函數(shù),而上述中的輸出語(yǔ)句 Point(const Point& p)和 ~Point()就是在創(chuàng)建這個(gè)返回值對(duì)象時(shí)調(diào)用的構(gòu)造函數(shù)以及當(dāng)返回值返回后調(diào)用的析構(gòu)函數(shù);而緊接著的輸出信息是 p++和 Point()以及~Point(),p++這個(gè)輸出信息自然是因?yàn)檎{(diào)用的后 ++重載運(yùn)算符函數(shù)的構(gòu)造函數(shù)而輸出的打印信息,那緊接著的 Point()和 ~Point()是因?yàn)樵诤?++重載運(yùn)算符函數(shù)中,創(chuàng)建的局部變量 Point n,進(jìn)而調(diào)用了 Point()函數(shù),以及函數(shù)退出之后,局部變量銷毀,調(diào)用了析構(gòu)函數(shù)。

上述詳細(xì)地分析了各個(gè)打印信息輸出的原因,通過(guò)上述的打印信息我們可以清楚知道程序在什么地方調(diào)用了構(gòu)造函數(shù),在什么地方調(diào)用了析構(gòu)函數(shù),再次回顧上述的函數(shù)調(diào)用過(guò)程,可以看出來(lái)其實(shí)調(diào)用的Point(const Point& p)和~Point()是多余的,那要如何改進(jìn)代碼呢,我們只需要將前 ++運(yùn)算符重載函數(shù)的返回值類型改為引用就行,這樣就不會(huì)創(chuàng)建臨時(shí)的變量,同時(shí)也就不會(huì)在調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù),改動(dòng)之后的代碼如下所示:

  1. Point& operator++(Point &p) 
  2.     cout<<"++p"<<endl; 
  3.     p.x += 1; 
  4.     p.y += 1; 
  5.     return p; 

那么上述代碼的運(yùn)行結(jié)果是什么呢?在主函數(shù)不變的情況下,輸出結(jié)果如下所示:

M4QzImA1uYxnBK9

可以看到上述結(jié)果中,之前在 ++p后輸出的兩條信息現(xiàn)在因?yàn)閷⒎祷刂翟O(shè)置為引用之后就消失了,說(shuō)明這樣的方法避免了調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù),節(jié)省了程序運(yùn)行的空間,那如果將后++重載函數(shù)設(shè)置為引用可不可行呢,很顯然,如果返回的是 n的引用,那么這在語(yǔ)法中就是錯(cuò)誤的,因?yàn)閚是局部變量,局部變量在函數(shù)調(diào)用結(jié)束就銷毀了,是不能作為引用對(duì)象的。如果返回的是 p呢,那么函數(shù)的運(yùn)行結(jié)果將發(fā)生改變,換句話說(shuō)就是不是實(shí)現(xiàn)的后 ++這個(gè)功能了。

最后,總結(jié)一下,對(duì)于一個(gè)函數(shù)來(lái)說(shuō),函數(shù)的返回結(jié)果如果作為值返回,那么代碼的執(zhí)行效率較低;如果作為引用返回,那么代碼的執(zhí)行效率較高,但是會(huì)存在一個(gè)問(wèn)題,引用返回可能會(huì)導(dǎo)致函數(shù)運(yùn)行出錯(cuò),所以,在保證函數(shù)運(yùn)行沒(méi)有錯(cuò)誤的前提下,為了提高效率應(yīng)該使用的是引用返回。

緊接著,我們知道我們?cè)谑褂?C++進(jìn)行編碼的時(shí)候,基本不會(huì)再采用 C語(yǔ)言中的語(yǔ)法 printf這個(gè)語(yǔ)句,隨之替代的是 cout這個(gè)語(yǔ)句,我們也知道我們使用 cout進(jìn)行輸出的時(shí)候,往往采用的是下面這樣的輸出方式:

  1. cout << "m=" << m << endl; /* 此時(shí) m 不是一個(gè)實(shí)例化對(duì)象 */ 

但是如果說(shuō)此時(shí) m 是一個(gè)實(shí)例化的對(duì)象,那么像上述這樣輸出就是存在問(wèn)題的,這個(gè)時(shí)候,就需要對(duì) <<運(yùn)算符進(jìn)行重載,重載的代碼如下所示:

  1. ostream& operator<<(ostream &o, Point p) 
  2.     cout<<"("<<p.x<<", "<<p.y<<")"
  3.     return o; 

稍微對(duì)上述代碼進(jìn)行一下解釋, 這里為什么返回值是ostream&呢,是因?yàn)閷?duì)于 cout來(lái)說(shuō),它是ostream類的實(shí)例化對(duì)象,在使用 cout進(jìn)行輸出的時(shí)候,它所遵循的一個(gè)輸出格式是 cout <<,因此,這里的返回值是 ostream。為什么返回值是引用呢,是為了滿足下面所示代碼的運(yùn)行,同時(shí)輸出了 m和 p1,結(jié)合上述代碼,我們來(lái)編寫主函數(shù),主函數(shù)代碼如下所示:

  1. int main(int argc, char **argv) 
  2.     Point p1(1,2); 
  3.     Point m; 
  4.     m = p1++; 
  5.     cout << "m =" << m << "p1 =" << p1 << endl;  

上述代碼的運(yùn)行結(jié)果如下所示:

1cGujg7yqZSIfpK

可以看到在重載了運(yùn)算符 <<之后,輸出實(shí)例化的對(duì)象也是可行的。

類內(nèi)實(shí)現(xiàn)運(yùn)算符重載函數(shù)

在上述代碼中我們實(shí)現(xiàn)的 +運(yùn)算符重載函數(shù)以及前 ++運(yùn)算符重載函數(shù)和后++運(yùn)算符重載函數(shù),都是在類外實(shí)現(xiàn)的,那么如果要在類內(nèi)實(shí)現(xiàn)以上幾個(gè)運(yùn)算符重載函數(shù),應(yīng)該如何寫呢,我們先回顧一下,在類外面實(shí)現(xiàn)的+運(yùn)算符重載函數(shù)的函數(shù)聲明如下所示:

  1. friend Point operator+(Point &p1, Point &p2); /* 因?yàn)樵陬愅庖軌蛟L問(wèn)類里面的數(shù)據(jù)成員,因此這里使用的是友元 */ 

上述是在類外實(shí)現(xiàn)運(yùn)算符重載函數(shù)時(shí)的函數(shù)原型,那么如果函數(shù)的定義就是在類里面實(shí)現(xiàn)的,函數(shù)又該如何編寫呢?首先,如果是在類里面實(shí)現(xiàn),那么當(dāng)前使用這個(gè)類進(jìn)行實(shí)例化的對(duì)象本身就可以使用 *this來(lái)表征一個(gè)對(duì)象,這個(gè)時(shí)候,如果要重載 +運(yùn)算符函數(shù),那么就只需要一個(gè)Point類的形參就行,代碼如下所示:

  1. class Point 
  2. private: 
  3.     int x; 
  4.     int y; 
  5. public
  6.     /* 省略相關(guān)構(gòu)造函數(shù)的代碼,可以結(jié)合前文補(bǔ)全 */ 
  7.     Point operator+(Point &p) 
  8.     { 
  9.         cout<<"operator+"<<endl; 
  10.         Point n; 
  11.         n.x = this->x + p.x; 
  12.         n.y = this->y + p.y; 
  13.         return n; 
  14.     } 

對(duì)比上述在類外面實(shí)現(xiàn)的代碼,對(duì)于重載的運(yùn)算符 +來(lái)說(shuō),只有一個(gè)形參了,而與其相加的另一個(gè)對(duì)象使用的是this來(lái)替代。依據(jù)這樣的一種思路,我們繼續(xù)將前 ++和后 ++重載的運(yùn)算符函數(shù)進(jìn)行改寫,改寫之后的代碼如下所示:

  1. class Point 
  2. private: 
  3.     int x; 
  4.     int y; 
  5. public
  6.     /* Point p(1,2); ++p */ 
  7.     Point& operator++(void) 
  8.     { 
  9.         cout<<"operator++(void)"<<endl; 
  10.         this->x += 1; 
  11.         this->y += 1; 
  12.         return *this; 
  13.     } 
  14.  
  15.     /* Point p(1,2); p++; */ 
  16.     Point operator++(int a) 
  17.     { 
  18.         cout<<"operator++(int a)"<<endl; 
  19.         Point n; 
  20.         n = *this; 
  21.         this->x += 1; 
  22.         this->y += 1; 
  23.         return n;    
  24.     } 
  25. }; 

結(jié)合上述的代碼,我們?cè)賮?lái)編寫主函數(shù),主函數(shù)的代碼如下所示:

  1. int main(int argc, char ** argv) 
  2.     Point p1(1,2); 
  3.     Point p2(2,3); 
  4.  
  5.     Point m; 
  6.     Point n; 
  7.  
  8.     cout << "begin" << endl; 
  9.     m = ++p1;    /* m = p1.operator++(); */ 
  10.     cout << "m =" << m << "p1 =" << p1 << endl; 
  11.     cout << "*********************" << endl; 
  12.  
  13.     n = p2++;    /* n = p2.operator++(0); */ 
  14.     cout << "n =" << n << "p2 =" << p2 << endl; 
  15.  
  16.     return 0; 

上述代碼中,注釋掉的代碼和沒(méi)注釋的代碼前后是等價(jià)的,只是說(shuō)注釋掉的代碼看起來(lái)更加直觀,更加容易理解其背后的原理,而注釋前的代碼則更加簡(jiǎn)潔。這里額外說(shuō)一點(diǎn),<<的重載函數(shù)是不能夠放到類內(nèi)實(shí)現(xiàn)的,因?yàn)檫@個(gè)重載函數(shù)的形參不是 Point類的,所以其只能在類外才能實(shí)現(xiàn)。

上述中,敘述了在類內(nèi)實(shí)現(xiàn)的重載運(yùn)算符函數(shù),接下來(lái)敘述一下 =運(yùn)算符在類內(nèi)實(shí)現(xiàn)的重載函數(shù),我們以之前所說(shuō)的 Person類來(lái)實(shí)現(xiàn)這個(gè)功能,Person類的代碼實(shí)現(xiàn)如下所示:

  1. class Person 
  2. private: 
  3.     char *name
  4.     int age; 
  5.     char *work
  6.  
  7. public
  8.     Person() 
  9.     { 
  10.         name = NULL
  11.         work = NULL
  12.     } 
  13.  
  14.    Person(char *nameint age, char *work
  15.    { 
  16.        this->age = age; 
  17.  
  18.        this->name = new char[strlen(name) + 1]; 
  19.        strcpy(this->name,name); 
  20.  
  21.        this->work = new char[strlen(work) + 1]; 
  22.        strcpy(this->workwork); 
  23.    } 
  24.  
  25.    /* 拷貝構(gòu)造函數(shù) */  
  26.    Person(Person &p) 
  27.    { 
  28.        this->age = p.age; 
  29.  
  30.        this->name = new char[strlen(p.name) + 1]; 
  31.        strcpy(this->name,p.name); 
  32.  
  33.        this->work = new char[strlen(p.work) + 1]; 
  34.        strcpy(this->work, p.work); 
  35.    } 
  36.  
  37.    ~Person() 
  38.    { 
  39.        if (this->name
  40.            delete this->name
  41.        if (this->work
  42.            delete this->work
  43.    } 
  44.  
  45.    void PrintInfo(void)  
  46.    { 
  47.        cout << "name =" << name << "age =" << age << "work =" << work << endl; 
  48.    } 

基于上述的代碼,我們可以書寫如下的主函數(shù)代碼:

  1. int main(int argc, char **argv) 
  2.     Person p1("zhangsan", 18, "doctor"); 
  3.     Person p2; 
  4.     p2 = p1; 

上述中,我們還沒(méi)有將 =運(yùn)算符進(jìn)行重載,就使用了 =實(shí)現(xiàn)了實(shí)例化對(duì)象的運(yùn)算,這樣會(huì)存在一個(gè)什么問(wèn)題呢,我們從源頭來(lái)進(jìn)行分析,=運(yùn)算符執(zhí)行的是值拷貝,那么在執(zhí)行了上述語(yǔ)句之后,p2和p1之間的關(guān)系是這樣的:

ywhv3zYKCaRjrXx

通過(guò)上述所示的圖片可以看出,如果不將 =進(jìn)行重載,那么會(huì)讓 p1和 p2的name 和 work指向同一塊內(nèi)存,這會(huì)造成什么問(wèn)題呢,如果此時(shí)已經(jīng)將 p1的內(nèi)存釋放掉了,而這個(gè)時(shí)候又要釋放 p2的內(nèi)存,這種情形就會(huì)出錯(cuò),同一塊內(nèi)存不能夠釋放兩次。

因此,就需要對(duì) =運(yùn)算符進(jìn)行重載,重載的代碼如下所示:

  1. /* 注意此處的代碼是在類里面實(shí)現(xiàn)的成員函數(shù),這里省略的一部分代碼 */ 
  2. Person& operator=(Person &p) 
  3.     if (this == &p) 
  4.         return *this; 
  5.     this->age = p.age; 
  6.  
  7.     if (this->name
  8.         delete this->name
  9.     if (this->work
  10.         delete this->work
  11.  
  12.     this->name = new char[strlen(p.name) + 1]; 
  13.     strcpy(this->name, p.name); 
  14.  
  15.     this->work = new char[strlen(p.work) + 1]; 
  16.     strcpy(this->work, p.work); 

這樣子就會(huì)避免上述情況的出現(xiàn),我們現(xiàn)在繼續(xù)來(lái)書寫主函數(shù):

  1. int main(int argc, char **argv) 
  2.     Person p1("zhangsan", 18, "doctor"); 
  3.  
  4.     cout<<"Person p2 = p1" <<endl; 
  5.     Person p2 = p1; 
  6.  
  7.     Person p3; 
  8.  
  9.     cout<<"p3=p1"<<endl; 
  10.     p3 = p1; 
  11.     cout<<"end"<<endl; 
  12.     p1.PrintInfo(); 
  13.     p2.PrintInfo(); 
  14.     p3.PrintInfo(); 
  15.  
  16.     return 0; 

上述主函數(shù)運(yùn)行的結(jié)果如下所示:

2kiKb8NEfYynTdo

通過(guò)上述代碼我們看到,實(shí)際上代碼 Person p2 = p1的運(yùn)行并不是調(diào)用的 = 的重載函數(shù),而是調(diào)用的拷貝構(gòu)造函數(shù),只有 p3= p1才是調(diào)用的 =的重載函數(shù)。

在本章節(jié)的最后,額外補(bǔ)充一點(diǎn),剛剛提到了拷貝構(gòu)造函數(shù),實(shí)際上拷貝構(gòu)造函數(shù)的形參大多數(shù)都是加了const修飾符的,也就是像如下所示的這樣子:

  1. Person& operator=(const Person &p) 

而這個(gè)時(shí)候,如果我們定義的 Person p1也是 const的,也就是像這樣:

  1. const Person p1("zhangsan", 18, "doctor"); 

那這個(gè)時(shí)候在使用 p1.PrintInfo()的時(shí)候就會(huì)出錯(cuò),因?yàn)榇藭r(shí)必須把該成員函數(shù)也表明為 const的才行,代碼如下所示:

  1. /* 類內(nèi)成員函數(shù),省略部分代碼 */ 
  2. void PrintInfo(void) const 
  3.     cout << "name =" << name << "age =" << age << "work =" << work << endl; 

總結(jié)一下也就是說(shuō):const對(duì)象只能夠調(diào)用const成員函數(shù),而const表示的是此函數(shù)沒(méi)有對(duì)當(dāng)前對(duì)象進(jìn)行修改

小結(jié)

上述就是本期教程分享的內(nèi)容,到本期教程截至,C++相對(duì)于 C語(yǔ)言不同的一些語(yǔ)法特性就到此結(jié)束了。下期教程將介紹 C++如何實(shí)現(xiàn)面向?qū)ο蟮姆椒ā1酒诮坛趟婕暗降拇a可以通過(guò)百度云鏈接的方式獲取到。

鏈接:https://pan.baidu.com/s/1BC55_QH-iV23-ON0v1OGSA

提取碼:iyf7

本文轉(zhuǎn)載自微信公眾號(hào)「wenzi嵌入式軟件」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系wenzi嵌入式軟件公眾號(hào)。

 

責(zé)任編輯:武曉燕 來(lái)源: wenzi嵌入式軟件
相關(guān)推薦

2021-02-21 12:09:32

C 語(yǔ)言基礎(chǔ)語(yǔ)法

2021-02-08 20:25:12

C 語(yǔ)言C++Linux

2021-02-11 08:25:17

C 語(yǔ)言C++ 基礎(chǔ)

2021-02-16 10:57:34

C++ C 語(yǔ)言windows

2021-07-16 07:21:45

C++可調(diào)用對(duì)象std::functi

2010-01-15 17:38:37

C++語(yǔ)言

2010-01-19 14:45:35

C++語(yǔ)言

2020-08-21 13:20:36

C++If ElseLinux

2021-04-25 08:11:57

C語(yǔ)言常量與變量標(biāo)識(shí)符命名規(guī)范

2011-07-14 17:45:06

CC++

2011-07-15 00:47:13

C++多態(tài)

2021-02-06 07:49:48

C語(yǔ)言編程開發(fā)技術(shù)

2011-07-14 22:52:27

C++typedef

2011-01-05 11:12:34

C++

2022-01-14 09:10:56

C++文件Linux

2011-07-13 18:24:18

C++

2020-07-30 12:40:35

CC++編程語(yǔ)言

2022-07-01 11:56:54

C語(yǔ)言C++編程語(yǔ)言

2010-01-22 15:30:36

C++語(yǔ)言

2024-02-21 14:55:19

C++語(yǔ)言編程
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)