運算子重載
所謂重載,就是重新賦予新的意義。函數重載就是對一個已有的函數賦予新的意義,使之實現新功能,因此,一個函數名稱就可以用來代表不同功能的函數,也就是」一名多用」。
運算符也可以重載。實際上,我們已經在不知不覺之中使用了運算子重載。例如,大家都已習慣於用加法運算子”+”對整數、單精度數和雙精度數進行加法運算,如5+8, 5.8 +3.67等,其實計算機對整數、單精度數和雙精度數的加法操作過程是很不相同的, 但由於C++已經對運算子”+”進行了重載,所以就能適用於int, float, doUble類型的運算。
C++中預先定義的運算子的操作物件只能是基本資料型別。但實際上,對於許多使用者自訂類型(例如類別),也需要類似的運算操作。這時就必須在C++中重新定義這些運算符,賦予已有運算符新的功能,使它能夠用於特定類型執行特定的操作。運算子重載的實質是函式重載,它提供了C++的可擴充性,也是C++最吸引人的特性之一。
運算子重載是透過建立運算子函數來實現的,運算子函數定義了重載的運算子將要進行的操作。運算子函數的定義與其他函數的定義類似,惟一的區別是運算子函數的函數名稱是由關鍵字operator和其後要重載的運算子符號構成的。運算子函數定義的一般格式如下:
operator ()
{ <函数体> }
運算子重載時要遵循下列規則:
(1) 除了類別屬關係運算符號"."、成員指標運算子".*"、作用域運算子"::"、sizeof運算子和三目運算子"?:"以外,C++中的所有運算子都可以重載。
(2) 重載運算子限制在C++語言中已有的運算子範圍內的允許重載的運算子之中,不能建立新的運算子。
(3) 運算子重載實質上是函數重載,因此編譯程式對運算子重載的選擇,遵循函數重載的選擇原則。
(4) 重載之後的運算子不能改變運算子的優先權和結合性,也不能改變運算子運算元的個數及語法結構。
(5) 運算子重載不能改變此運算子用於內部類型物件的意義。它只能和使用者自訂類型的物件一起使用,或用於使用者自訂類型的物件和內部類型的物件混合使用時。
(6) 運算子重載是針對新類型資料的實際需求對原有運算子進行的適當的改造,重載的功能應與原有功能相類似,避免沒有目的地使用重載運算子。
運算子函數重載一般有兩種形式:重載為類別的成員函數和重載為類別的非成員函數。非成員函數通常是友元。 (可以把一個運算子當作一個非成員、非友元函數重載。但是,這樣的運算子函數存取類別的私有和保護成員時,必須使用類別的公有介面中提供的設定資料和讀取資料的函數,呼叫這些函數時會降低效能。的成員函數時,函數的參數個數比原來的操作數要少一個(後置單目運算子除外),這是因為成員函數用this指針隱式地訪問了類的一個對象,它充當了運算符函數最左邊的運算元。因此:
(1) 雙目運算子重載為類別的成員函數時,函數只明確說明一個參數,該形參是運算子的右操作數。
(2) 前置單目運算子重載為類別的成員函數時,不需要明確說明參數,即函數沒有形參。
(3) 後置單目運算子重載為類別的成員函數時,函數要帶有一個整數形參。
調用成員函數運算子的格式如下:
<函数类型> operator <运算符>(<参数表>) { <函数体> }
<对象名>.operator <运算符>(<参数>)
運算子重載為類別的友元函數的一般格式為:
<对象名><运算符><参数>
調用友元函數運算符的格式如下:
friend <函数类型> operator <运算符>(<参数表>) { <函数体> }
operator <运算符>(<参数1>,<参数2>)
), 它等價於
<参数1><运算符><参数2>
).
在多数情况下,将运算符重载为类的成员函数和类的友元函数都是可以的。但成员函数运算符与友元函数运算符也具有各自的一些特点:
(1) 一般情况下,单目运算符最好重载为类的成员函数;双目运算符则最好重载为类的友元函数。
(2) 以下一些双目运算符不能重载为类的友元函数:=、()、[]、->。
(3) 类型转换函数只能定义为一个类的成员函数而不能定义为类的友元函数。
(4) 若一个运算符的操作需要修改对象的状态,选择重载为成员函数较好。
(5) 若运算符所需的操作数(尤其是第一个操作数)希望有隐式类型转换,则只能选用友元函数。
(6) 当运算符函数是一个成员函数时,最左边的操作数(或者只有最左边的操作数)必须是运算符类的一 个类对象(或者是对该类对象的引用)。如果左边的操作数必须是一个不同类的对象,或者是一个内部 类型的对象,该运算符函数必须作为一个友元函数来实现。
(7) 当需要重载运算符具有可交换性时,选择重载为友元函数。
1 为什么会用运算符重载机制(回忆函数重载)
用复数类举例 //Complex c3 =c1 + c2;
//原因 Complex是用户自定义类型,编译器根本不知道如何进行加减
//编译器给提供了一种机制,让用户自己去完成,自定义类型的加减操作。。。。。
//这个机制就是运算符重载机制
2 运算符重载的本质是一个函数
例如1:
//通过类成员函数完成 - 操作符重载(函数的定义在类里面) //函数声明 Complex operator-(Complex &c2) //用类成员函数实现-运算符重载 Complex c4 = c1 - c2; c4.printCom(); //打印输出 //c1.operator-(c2);
例如2:
//通过全局函数方法完成+操作符重载(函数的定义在类外) //函数声明 Complex operator+(Complex &c1, Complex &c2) //函数调用分析 int main() { Complex c1(1, 2), c2(3, 4);//定义两个对象 //Complex c31 = operator+(c1,c2); 函数的调用模式 Complex c3 = c1 + c2; //简写+ c3.printCom(); }
感受操作过程:
例如3:
//前置++操作符 用全局函数实现 Complex& operator++(Complex&c1) { c1.a ++; c1.b ++; return c1; } //调用方法 ++c1 ; //=è需要写出操作符重载函数原形 c1.printCom(); //运算符重载函数名定义 //首先承认操作符重载是一个函数 定义函数名--->operator++ //分析函数参数 根据左右操作数的个数------->operator++(Complex &c1) //分析函数返回值-------> Complex&operator++(Complex &c1) 返回它自身
例如4
//4.1 前置—操作符成员函数实现 Complex& operator--() { this->a--; this->b--; return *this; //注意返回 } //4.2 调用方法 --c1; c1.printCom(); //4.3前置—运算符重载函数名定义 //c1.operator--()
例如5:
//5.1//后置++ 操作符用全局函数实现 Complex operator++(Complex &c1, int) { Complex tmp = c1; c1.a++; c1.b++; return tmp; } //5.2 调用方法 c1 ++ ; //先使用后++ //5.3 后置++运算符重载函数名定义 Complex operator++(Complex&c1, int) //函数占位参数 和 前置++ 相区别
例如6:
//6.1 后置— 操作符 用类成员函数实现 Complexoperator--(int) { Complextmp = *this; this->a--; this->b--; return tmp; } //6.2 调用方法 c1 ++ ; //先使用后++ //6.3 后置--运算符重载函数名定义 Complex operator--(int) //函数占位参数和 前置-- 相区别
前置和后置运算符总结
C++中通过一个占位参数来区分前置运算和后置运算
定义运算符重载函数名的步骤
全局函数、类成员函数方法实现运算符重载步骤
1)要承认操作符重载是一个函数,写出函数名称operator+ ()
2)根据操作数,写出函数参数
3)根据业务,完善函数返回值(看函数是返回引用 还是指针 元素),及实现函数业务
友元函数实现操作符重载的应用场景
1)友元函数和成员函数选择方法 Ø 当无法修改左操作数的类时,使用全局函数进行重载 Ø =, [], ()和->操作符只能通过成员函数进行重载 2)用友元函数重载 << >>操作符 Ø istream 和 ostream 是 C++ 的预定义流类 Ø cin 是 istream 的对象,cout 是 ostream 的对象 Ø 运算符 << 由ostream 重载为插入操作,用于输出基本类型数据 Ø 运算符 >> 由 istream 重载为提取操作,用于输入基本类型数据 Ø 用友员函数重载 << 和 >> ,输出和输入用户自定义的数据类型 a)用全局函数方法实现 << 操作符 ostream& operator<<(ostream &out, Complex &c1) { //out<<"12345,生活真是苦"<<endl; out<<c1.a<<"+ "<<c1.b<<"i "<<endl; return out; } //调用方法 cout<<c1; //链式编程支持 cout<<c1<<"abcc"; //cout.operator<<(c1).operator<<("abcd"); //函数返回值充当左值 需要返回一个引用 b)类成员函数方法无法实现 <<操作符重载 //因拿到cout这个类的源码 //cout.operator<<(c1); 3) 友元函数重载操作符使用注意点 a) 友员函数重载运算符常用于运算符的左右操作数类型不同的情况 b)其他 Ø 在第一个参数需要隐式转换的情形下,使用友员函数重载运算符是正确的选择 Ø 友员函数没有 this 指针,所需操作数都必须在参数表显式声明,很容易实现类型的隐式转换 Ø C++中不能用友员函数重载的运算符有 = () [] ->
请问:为什么运算法重载成员函数只有一个参数,而友元函数有两个?
由于成员函数有指向对象的this指针,可以通过对象传递参数;而友元函数没有this指针,所以必须要两个参数。(针对二元操作符重载而言)
以上就是c++复习要点总结之七——运算符重载的内容,更多相关内容请关注PHP中文网(www.php.cn)!