日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當前位置:首頁 > > wenzi嵌入式軟件
[導讀]在上一則教程中,我們講述了重載運算符中前 ++和后++的重載函數(shù)的實現(xiàn),闡述了在 C++中可以將運算符進行重載的方法,這種方法大大地便利了程序員編寫代碼,在接下來地敘述中,我們將著重講述運算符重載時地一些更為細致地內容,其中就包括當重載地運算符返回值為引用和非引用兩種狀態(tài)時,代碼執(zhí)行效率地高低以及采用在類內實現(xiàn)運算符重載函數(shù)的方法。

前言

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

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

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

class?Point
{

private:
????int?x;
????int?y;

public:
????Point()?
????{
????????cout<<"Point()"<<endl;
????}
????Point(int?x,?int?y)?:?x(x),?y(y)?
????{
????????cout<<"Point(int?x,?int?y)"<<endl;
????}

????Point(const?Point&?p)
????{
????????cout<<"Point(const?Point&?p)"<<endl;
????????x?=?p.x;
????????y?=?p.y;
????}
????~Point()?
????{
????????cout<<"~Point()"<<endl;
????}

????friend?Point?operator++(Point?&p);
????friend?Point?operator++(Point?&p,?int?a);

????void?printInfo()
????
{
????????cout<<"("<",?"<")"<<endl;
????}
};

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

/*?++p?*/
Point?operator++(Point?&p)
{
????cout?<"++p"?<endl;
????p.x?+=?1;
????p.y?+=?1;
????return?p;
}

/*?p++?*/
Point?operator++(Point?&p,?int?a)
{
????cout?<"p++"?<endl;
????Point?n;
????n?=?p;
????p.x?+=?1;
????p.y?+=?1;
????return?n;
}

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

int?main(int?argc,?char?**argv)
{
????Point?p1(1,?2);

????cout<<"begin"<<endl;
????++p1;
????cout?<"******************"<<endl;

????p1++;
????cout<<"end"<<endl;

????return?0;
}

上述代碼的運行結果如下所示:

lhp7d3H1crAE9u2

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

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

Point&?operator++(Point?&p)
{
????cout<<"++p"<<endl;
????p.x?+=?1;
????p.y?+=?1;
????return?p;
}

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

M4QzImA1uYxnBK9

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

最后,總結一下,對于一個函數(shù)來說,函數(shù)的返回結果如果作為值返回,那么代碼的執(zhí)行效率較低;如果作為引用返回,那么代碼的執(zhí)行效率較高,但是會存在一個問題,引用返回可能會導致函數(shù)運行出錯,所以,在保證函數(shù)運行沒有錯誤的前提下,為了提高效率應該使用的是引用返回。

緊接著,我們知道我們在使用?C++進行編碼的時候,基本不會再采用?C語言中的語法?printf這個語句,隨之替代的是?cout這個語句,我們也知道我們使用?cout進行輸出的時候,往往采用的是下面這樣的輸出方式:

cout?<"m="?<endl;?/*?此時?m?不是一個實例化對象?*/

但是如果說此時 m 是一個實例化的對象,那么像上述這樣輸出就是存在問題的,這個時候,就需要對?<<運算符進行重載,重載的代碼如下所示:

ostream&?operator<<(ostream?&o,?Point?p)
{
????cout<<"("<",?"<")";
????return?o;
}

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

int?main(int?argc,?char?**argv)
{
????Point?p1(1,2);
????Point?m;
????m?=?p1++;
????cout?<"m?="?<"p1?="?<endl;?
}

上述代碼的運行結果如下所示:

1cGujg7yqZSIfpK

可以看到在重載了運算符?<<之后,輸出實例化的對象也是可行的。

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

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

friend?Point?operator+(Point?&p1,?Point?&p2);?/*?因為在類外要能夠訪問類里面的數(shù)據(jù)成員,因此這里使用的是友元?*/

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

class?Point
{

private:
????int?x;
????int?y;
public:
????/*?省略相關構造函數(shù)的代碼,可以結合前文補全?*/
????Point?operator+(Point?&p)
????{
????????cout<<"operator+"<<endl;
????????Point?n;
????????n.x?=?this->x?+?p.x;
????????n.y?=?this->y?+?p.y;
????????return?n;
????}
}

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

class?Point
{

private:
????int?x;
????int?y;
public:
????/*?Point?p(1,2);?++p?*/
????Point&?operator++(void)
????{
????????cout<<"operator++(void)"<<endl;
????????this->x?+=?1;
????????this->y?+=?1;
????????return?*this;
????}

????/*?Point?p(1,2);?p++;?*/
????Point?operator++(int?a)
????{
????????cout<<"operator++(int?a)"<<endl;
????????Point?n;
????????n?=?*this;
????????this->x?+=?1;
????????this->y?+=?1;
????????return?n;???
????}
};

結合上述的代碼,我們再來編寫主函數(shù),主函數(shù)的代碼如下所示:

int?main(int?argc,?char?**?argv)
{
????Point?p1(1,2);
????Point?p2(2,3);

????Point?m;
????Point?n;

????cout?<"begin"?<endl;
????m?=?++p1;????/*?m?=?p1.operator++();?*/
????cout?<"m?="?<"p1?="?<endl;
????cout?<"*********************"?<endl;

????n?=?p2++;????/*?n?=?p2.operator++(0);?*/
????cout?<"n?="?<"p2?="?<endl;

????return?0;
}

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

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

class?Person
{

private:
????char?*name;
????int?age;
????char?*work;

public:
????Person()
????{
????????name?=?NULL;
????????work?=?NULL;
????}

???Person(char?*name,?int?age,?char?*work)
???{
???????this->age?=?age;

???????this->name?=?new?char[strlen(name)?+?1];
???????strcpy(this->name,name);

???????this->work?=?new?char[strlen(work)?+?1];
???????strcpy(this->work,?work);
???}

???/*?拷貝構造函數(shù)?*/?
???Person(Person?&p)
???{
???????this->age?=?p.age;

???????this->name?=?new?char[strlen(p.name)?+?1];
???????strcpy(this->name,p.name);

???????this->work?=?new?char[strlen(p.work)?+?1];
???????strcpy(this->work,?p.work);
???}

???~Person()
???{
???????if?(this->name)
???????????delete?this->name;
???????if?(this->work)
???????????delete?this->work;
???}

???void?PrintInfo(void)?
???
{
???????cout?<"name?="?<"age?="?<"work?="?<endl;
???}
}

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

int?main(int?argc,?char?**argv)
{
????Person?p1("zhangsan",?18,?"doctor");
????Person?p2;
????p2?=?p1;
}

上述中,我們還沒有將?=運算符進行重載,就使用了?=實現(xiàn)了實例化對象的運算,這樣會存在一個什么問題呢,我們從源頭來進行分析,=運算符執(zhí)行的是值拷貝,那么在執(zhí)行了上述語句之后,p2p1之間的關系是這樣的:

ywhv3zYKCaRjrXx

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

因此,就需要對?=運算符進行重載,重載的代碼如下所示:

???/*?注意此處的代碼是在類里面實現(xiàn)的成員函數(shù),這里省略的一部分代碼?*/
???Person&?operator=(Person?&p)
???{
???????if?(this?==?&p)
???????????return?*this;
???????this->age?=?p.age;

???????if?(this->name)
???????????delete?this->name;
???????if?(this->work)
???????????delete?this->work;

???????this->name?=?new?char[strlen(p.name)?+?1];
???????strcpy(this->name,?p.name);

???????this->work?=?new?char[strlen(p.work)?+?1];
???????strcpy(this->work,?p.work);
???}

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

int?main(int?argc,?char?**argv)
{
????Person?p1("zhangsan",?18,?"doctor");

????cout<<"Person?p2?=?p1"?<<endl;
????Person?p2?=?p1;

????Person?p3;

????cout<<"p3=p1"<<endl;
????p3?=?p1;
????cout<<"end"<<endl;
????p1.PrintInfo();
????p2.PrintInfo();
????p3.PrintInfo();

????return?0;
}

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

2kiKb8NEfYynTdo

通過上述代碼我們看到,實際上代碼?Person p2 = p1的運行并不是調用的?=?的重載函數(shù),而是調用的拷貝構造函數(shù),只有?p3= p1才是調用的?=的重載函數(shù)。

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

Person&?operator=(const?Person?&p)

而這個時候,如果我們定義的?Person p1也是?const的,也就是像這樣:

const?Person?p1("zhangsan",?18,?"doctor");

那這個時候在使用?p1.PrintInfo()的時候就會出錯,因為此時必須把該成員函數(shù)也表明為?const的才行,代碼如下所示:

???/*?類內成員函數(shù),省略部分代碼?*/
???void?PrintInfo(void)?const
???
{
???????cout?<"name?="?<"age?="?<"work?="?<endl;
???}

總結一下也就是說:const對象只能夠調用const成員函數(shù),而const表示的是此函數(shù)沒有對當前對象進行修改

小結

上述就是本期教程分享的內容,到本期教程截至,C++相對于?C語言不同的一些語法特性就到此結束了。下期教程將介紹?C++如何實現(xiàn)面向對象的方法。本期教程所涉及到的代碼可以通過百度云鏈接的方式獲取到。

鏈接:https://pan.baidu.com/s/1BC55_QH-iV23-ON0v1OGSA
提取碼:iyf7


免責聲明:本文內容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關機構授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內容真實性等。需要轉載請聯(lián)系該專欄作者,如若文章內容侵犯您的權益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關鍵字: 驅動電源

在工業(yè)自動化蓬勃發(fā)展的當下,工業(yè)電機作為核心動力設備,其驅動電源的性能直接關系到整個系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護是驅動電源設計中至關重要的兩個環(huán)節(jié),集成化方案的設計成為提升電機驅動性能的關鍵。

關鍵字: 工業(yè)電機 驅動電源

LED 驅動電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個照明設備的使用壽命。然而,在實際應用中,LED 驅動電源易損壞的問題卻十分常見,不僅增加了維護成本,還影響了用戶體驗。要解決這一問題,需從設計、生...

關鍵字: 驅動電源 照明系統(tǒng) 散熱

根據(jù)LED驅動電源的公式,電感內電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關鍵字: LED 設計 驅動電源

電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動汽車的核心技術之一是電機驅動控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機驅動系統(tǒng)中的關鍵元件,其性能直接影響到電動汽車的動力性能和...

關鍵字: 電動汽車 新能源 驅動電源

在現(xiàn)代城市建設中,街道及停車場照明作為基礎設施的重要組成部分,其質量和效率直接關系到城市的公共安全、居民生活質量和能源利用效率。隨著科技的進步,高亮度白光發(fā)光二極管(LED)因其獨特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關鍵字: 發(fā)光二極管 驅動電源 LED

LED通用照明設計工程師會遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關鍵字: LED 驅動電源 功率因數(shù)校正

在LED照明技術日益普及的今天,LED驅動電源的電磁干擾(EMI)問題成為了一個不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關鍵字: LED照明技術 電磁干擾 驅動電源

開關電源具有效率高的特性,而且開關電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機重量也有所下降,所以,現(xiàn)在的LED驅動電源

關鍵字: LED 驅動電源 開關電源

LED驅動電源是把電源供應轉換為特定的電壓電流以驅動LED發(fā)光的電壓轉換器,通常情況下:LED驅動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關鍵字: LED 隧道燈 驅動電源
關閉