詳解C++中賦值,關(guān)系,函數(shù)調(diào)用運(yùn)算符重載的實現(xiàn)
賦值運(yùn)算符重載
在C++中基本數(shù)據(jù)類型例如整型,可以實現(xiàn)連續(xù)賦值:a=b=c;而我們的對象的成員屬性雖然可以相等,但是如果牽扯到堆地址,就會有深淺拷貝的問題存在。所以我們自己重載賦值運(yùn)算符,實現(xiàn)連等的方法。
類結(jié)構(gòu)
class Info { int* m_a; public: Info() { m_a = NULL; } Info(int a) { m_a = new int(a); } ~Info() { if (m_a != NULL) delete m_a; m_a = NULL; } };
創(chuàng)建一個Info類,定義指針屬性*m_a, 然后自己定義Info類的無參、有參構(gòu)造函數(shù)和析構(gòu)函數(shù),再給屬性賦值的時候,是用new關(guān)鍵字開辟堆區(qū)并存放數(shù)據(jù);析構(gòu)在前面的文章中講到了他的作用,就是在程序結(jié)束前編譯器自動調(diào)用析構(gòu)來完成對象的清理工作,在這里就會把堆區(qū)的數(shù)據(jù)釋放掉。
問題的出現(xiàn)
Info f(20); Info f1; Info f2; Info f3(30); f1 = f2 =f;
直接連等是不行的,因為在析構(gòu)函數(shù)里訪問了一個NULL地址,就比如程序即將結(jié)束,f調(diào)用析構(gòu)函數(shù),刪除m_a指向的地址,然而f1也會調(diào)用析構(gòu)函數(shù),由于f1和f的m_a指向同一個地址,那就好重復(fù)訪問,訪問一個被刪除的地址肯定會報錯的;因此我們需要對賦值運(yùn)算符進(jìn)行重載,這里提示一下,連等就相當(dāng)于鏈?zhǔn)秸{(diào)用,因此重載運(yùn)算符的返回值類型需要返回引用。
具體實現(xiàn)
Info& operator=(Info& f) { if (m_a != NULL) delete m_a; m_a = NULL; m_a = new int(*f.m_a); return *this; }
返回值類型是類引用,這樣可以做到鏈?zhǔn)秸{(diào)用 ,函數(shù)名還是統(tǒng)一的operator+運(yùn)算符,既然是賦值運(yùn)算符就用operator=,然后這個重載發(fā)生在成員內(nèi)部,因此參數(shù)里只需要傳入用來賦值的對象即可,注意倒數(shù)第二行代碼,我利用new讓m_a指向堆區(qū)中新開辟的地址,這是賦值運(yùn)算符重載的關(guān)鍵;就是因為把地址指向了堆區(qū)的新地址,這樣不同的對象在調(diào)用析構(gòu)函數(shù)的時候各刪各的堆地址,不會訪問空地址,這個問題的解決和深淺拷貝的解決方式一樣,都是自己寫方法來避免原來方法中成員屬性指向同一個地址。最后返回自身的引用,就可以實現(xiàn)連續(xù)調(diào)用了。
關(guān)系運(yùn)算符重載
關(guān)系運(yùn)算符有“大于”、“小于”、“等于”、“大于等于”、“不等于”等幾種情況,我就舉例等于和不等于兩種賦值運(yùn)算符重載的例子
類結(jié)構(gòu)
class Info { friend void test1(); int* m_a; string m_name; public: Info() { m_a = NULL; } Info(int a,string name) { m_a = new int(a); m_name = name; } ~Info() { if (m_a != NULL) delete m_a; m_a = NULL; } }
這里的類結(jié)構(gòu)相比于賦值運(yùn)算符重載多了一個String類型的m_name屬性,然后寫出類的無參、有參構(gòu)造和析構(gòu)函數(shù),最上面的friend關(guān)鍵字是加了一個友元的聲明,讓下面的test1函數(shù)可以訪問類的私有屬性。
具體實現(xiàn)
bool operator==(Info& f) { if (*this->m_a == *f.m_a && m_name==f.m_name) return true; else return false; } bool operator!=(Info& f) { if (*this->m_a == *f.m_a && m_name == f.m_name) return false; else return true; }
返回值類型寫成布爾類型,因為關(guān)系運(yùn)算的結(jié)果就是布爾類型的,常和while循環(huán)以及if語句使用;函數(shù)名還是老樣子,operator==和operator!=,分別是相等和不等;既然是成員內(nèi)部的關(guān)系運(yùn)算符重載,那么形參傳入一個待比較對象即可。
調(diào)用方法
void test1() { Info f1(20,"張三"); Info f3(30,"張六"); if (f1== f3) cout << "二者相等" << endl; else if (f1!= f3) cout << "二者不相等" << endl; }
運(yùn)行效果
函數(shù)調(diào)用運(yùn)算符重載
函數(shù)調(diào)用使用“()”,函數(shù)調(diào)用也是可以重載的,而且重載的調(diào)用很像直接調(diào)用函數(shù),因此也叫做仿函數(shù)。
類結(jié)構(gòu)
class MyHello { public: string hello; };
非常簡單的類結(jié)構(gòu),只有一個公有權(quán)限下的String類型的hello屬性。
具體實現(xiàn)
void operator()(string s) { cout << s << endl; }
因為只是打印一下,不需要返回值,函數(shù)名不多說了,和前面類似,然后傳入字符串類型再方法里打印出來。
調(diào)用方法
void test() { MyHello hello; hello("Hello World"); }
首先創(chuàng)建類對象hello,直接使用重載后的調(diào)用方法:對象+(字符串);這樣就能打印出引號里的內(nèi)容了:
匿名對象調(diào)用
最后補(bǔ)充一個匿名對象的知識,示例:
class MyAdd { public: int operator()(int num1, int num2) { return num1 + num2; } }; void test1() { MyAdd myAdd; int num = myAdd(160, 40); cout << "ret =" << myAdd(160,40) << endl; cout << "ret =" << MyAdd()(100,50) << endl; }
這里我寫了一個只有重載函數(shù)調(diào)用函數(shù)的類,并在test1中用常規(guī)和匿名對象調(diào)用重載后的函數(shù)調(diào)用方法;看一下運(yùn)行效果:
先創(chuàng)建對象,再通過對象調(diào)用函數(shù)的方法我們不感到奇怪,但是最后一個輸出語句中,MyAdd()(100,50)是什么意思呢 ,這就是匿名對象,往后我們遇到形如類名+()再+調(diào)用函數(shù)的方式,那就是創(chuàng)建了匿名對象,其特點(diǎn)就是創(chuàng)建完畢后就會刪除,這里我們只都一下數(shù)據(jù),所以適合匿名對象的調(diào)用。
總結(jié)
到這里C++的運(yùn)算符重載徹底結(jié)束了,運(yùn)算符重載可以多個都重載并互相配合使用,把對象的屬性可以和基本類型一樣進(jìn)行算數(shù)運(yùn)算和邏輯運(yùn)算,在類對象比較多的時候可以節(jié)省很多時間,簡化程序。
以上就是詳解C++中賦值,關(guān)系,函數(shù)調(diào)用運(yùn)算符重載的實現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于C++運(yùn)算符重載的資料請關(guān)注腳本之家其它相關(guān)文章!