操作符重載,也叫運算符重載,是C++的重要組成部分,它可以讓程序更加的簡單易懂,簡單的運算符使用可以使復雜函數的理解更直觀。
雖然運算符重載聽起來好像是C++的外部能力,但是多數程序員都不知不覺地使用過重載的運算符。例如,加法運算符“+”對整數、單精度數和雙精度數的操作是大不相同的。這是因為C++語言本身已經重載了該運算符,所以它能夠用於int、float、double和其它內部定義類型的變量。
操作符重載可對已有的運算符(C++中預定義的運算符)賦予多重的含義,使同一運算符作用於不同類型的數據時導致不同類型的行為。
其目的是:擴展C++中提供的運算符的適用范圍,以用於類所表示的抽象數據類型。同一個運算符,對不同類型的操作數,所發生的行為不同。
操作符被重載的基本前提:
1.只能為自定義類型重載操作符;
2.不能對操作符的語法(優先級、結合性、操作數個數、語法結構) 、語義進行顛覆;
3.不能引入新的自定義操作符。
不允許在用戶自定義類型中重載的操作符:
允許在用戶自定義類型中重載的操作符:
1.操作符重載的定義
在用戶自定義類型中使用操作符來表示所提供的某些操作,可以收到同樣的效果,但前提是它們與基本類型用操作符表示的操作、與其他用戶自定義類型用操作符表示的操作之間不存在沖突與二義性。(即在某一特定位置上,某一操作符應具有確定的、唯一的含義)
編譯程序能夠對是否存在沖突與二義性作出判斷的依據,是類型及其操作集。
例:
#include <iostream> using namespace std; class Complex { public: Complex( ) { real=0; imag=0; } Complex(double r,double i) { real=r; imag=i; } Complex complex_add(Complex &c2); //聲明復數相加函數 void display( ); private: double real; //實部 double imag; //虛部 }; Complex Complex::complex_add(Complex &c2) { Complex c; c.real=real+c2.real; c.imag=imag+c2.imag; return c; } void Complex::display( ) { cout<<"("<<real<<","<<imag<<"i)"<<endl; } int main( ) { Complex c1(1,2),c2(3,-4),c3; //定義3個復數對象 c3=c1.complex_add(c2); //調用復數相加函數 cout<<"c1="; c1.display( ); //輸出c1的值 cout<<"c2="; c2.display( ); //輸出c2的值 cout<<"c1+c2="; c3.display( ); //輸出c3的值 return 0; }
程序執行結果:
c1=(1,2i)
c2=(3,-4i)
c1+c2=(4,-2i)
運算符重載的方法是定義一個重載運算符的函數,在需要執行被重載的運算符時,系統就自動調用該函數,以實現相應的運算。從某種程度上看,運算符重載也是函數的重載。但運算符重載的關鍵並不在於實現函數功能,而是由於每種運算符都有其約定俗成的含義,重載它們應是在保留原有含義的基礎上對功能的擴展,而非改變。
重載運算符的函數一般格式如下:
函數類型 operator 運算符名稱 (形參表列) { 對運算符的重載處理 }
例如,想將“+”用於Complex類(復數)的加法運算,函數的原型可以是這樣的:
Complex operator+ (Complex& c1,Complex& c2);
operator是c++的關鍵字,專門用於定義重載運算符的函數。operator +就是函數名,表示對運算符+重載。
例:
class Complex { public: Complex( double = 0.0, double = 0.0 ); Complex operator+( const Complex & ) const; Complex operator-( const Complex & ) const; private: double real; // real part double imaginary; // imaginary part }; Complex Complex::operator+( const Complex &operand2 ) const { return Complex( real + operand2.real, imaginary + operand2.imaginary ); } Complex Complex::operator-( const Complex &operand2 ) const { return Complex( real - operand2.real, imaginary - operand2.imaginary ); }
在上例中,+和-運算符重載實際上是有着2個參數,但由於重載函數是類中的成員函數,有一個參數是隱含的,函數是用this指針隱式地訪問類對象的成員。
例如
c3=c1+c2
最后在C++編譯系統中被解釋為:
c3=c1.operator+(c2)
在此例中,operator+是類的成員函數。第一操作數為“*this(c1)”,第二操作數為“參數(c2)”。
實質操作符的重載就是函數的重載,在程序編譯時把指定的運算表達式轉換成對運算符的調用,把運算的操作數轉換成運算符函數的參數,根據實參的類型決定調用哪個操作符函數。
對於單目運算符++和--有兩種使用方式,前置運算和后置運算,它們是不同的。針對這一特性,C++約定:如果在自增(自減)運算符重載函數中,無參數表示前置運算符函數,若加一個int型形參,就表示后置運算符函數。
例:
有一個Time類,包含數據成員minute(分)和sec(秒),模擬秒表,每次走一秒,滿60秒進一分鍾,此時秒又從0開始算。要求輸出分和秒的值。
class Time { public: Time( ){minute=0;sec=0;} Time(int m,int s):minute(m),sec(s){ } Time operator++( ); //聲明前置自增運算符“++”重載函數 Time operator++(int); //聲明后置自增運算符“++”重載函數 private: int minute; int sec; }; Time Time::operator++( ) //定義前置自增運算符“++”重載函數 { if(++sec>=60) { sec-=60; //滿60秒進1分鍾 ++minute; } return *this; //返回當前對象值 } Time Time::operator++(int) //定義后置自增運算符“++”重載函數 { Time temp(*this); sec++; if(sec>=60) { sec-=60; ++minute; } return temp; //返回的是自加前的對象 }
在代碼 Time operator++(int)中,注意有個int,在這里int並不是真正的參數,也不代表整數,只是一個用來表示后綴的標志!!
2.運算符重載函數的兩種形式
運算符重載的函數一般地采用如下兩種形式:成員函數形式和友元函數形式。這兩種形式都可訪問類中的私有成員。
友元函數是一種對面對對象程序中類的破壞,可以訪問私有成員。
重載為友元函數的運算符重載函數的定義格式如下:
friend函數類型 operator 運算符名稱 (形參表列) { 對運算符的重載處理 }
下面用友元函數的形式重載上例:
#include <iostream> using namespace std; class Complex { public: Complex( ) { real=0; imag=0; } Complex(double r,double i) { real=r; imag=i; } friend Complex operator + (Complex &c1,Complex &c2); void display( ); private: double real; double imag; }; Complex Complex::operator+( const Complex &operand2 ) const { return Complex( real + operand2.real, imag + operand2.imag ); } Complex operator + (Complex &c1,Complex &c2) { return Complex(c1.real+c2.real, c1.imag+c2.imag); }
例如
c3=c1+c2
最后在C++編譯系統中被解釋為:
c3=c1.operator+(c2)
運算符左側的操作數與函數第一個參數對應,右側的和第二個參數對應。
當重載友元函數時,將沒有隱含的參數this指針。這樣,對於雙面運算符,友元函數有2個參數,對於單目運算符,友元函數有一個參數。
注意:當同時存在2種形式的定義時,二者也是重載
例:
#include <iostream> using namespace std; class Complex { public: Complex( ) { real=0; imag=0; } Complex(double r,double i) { real=r; imag=i; } Complex operator+( const Complex & ) const; //重載為成員函數 friend Complex operator+(Complex &c1,Complex &c2); //重載為友員函數 void display( ); private: double real; double imag; }; int main( ) { Complex x, y, z; z = x + y; // x.operator+(y) x + 1.0; // operator+( x, 1.0 ) 1.0 + x; // error }
任何用戶自定義的隱式轉換都不會應用到操作符 . 的左操作數。
對>> and <<的重載
在C++中,系統重載了操作符>>-輸入操作 。
成員方法形式
istream& istream::operator>>(short& _Val); istream& istream::operator>>(unsigned short& _Val); istream& istream::operator>>(int& _Val); istream& istream::operator>>(unsigned int& _Val); istream& istream::operator>>(long& _Val); istream& istream::operator>>(unsigned long& _Val); istream& istream::operator>>(void *& _Val);
為自定義類重載操作>>並表示輸入操作時,也應采用非成員方式:
istream& operator>>( istream& in, Complex& c ) { in >> c.real >> c.imag; return in; }
Complex c1, c2; cin >> c1; cin >> c2;
class Complex { // 函數訪問Complex的非public成員時,必為友元 friend istream& operator>>(istream&, Complex&); // ... };
重載輸出操作符<<的要求和形式與重載輸入操作符>>相似。
實例:
#include <iostream> #include <string> using namespace std; class Student { friend ostream &operator<<(ostream &,const Student &); friend istream &operator>>(istream &,Student &); public: int num; int age; string sex; string name; }; ostream &operator<<(ostream &output,const Student &s) { cout<<"學號\t"<<"姓名\t"<<"性別\t"<<"年齡\t"<<endl; output<<s.num<<"\t"<<s.name<<"\t"<<s.sex<<"\t"<<s.age<<endl; return output; } istream &operator>>(istream &input,Student &s) { cout<<"學號:"; input>>s.num; cout<<"姓名:"; input>>s.name; cout<<"性別:"; input>>s.sex; cout<<"年齡:"; input>>s.age; return input; } int main() { Student stu; cout<<"Enter Student info:"<<endl; cin>>stu; cout<<"Print Student info:"<<endl; cout<<stu; return 0; }
程序執行結果:
Enter Student info: 學號:2017211758 姓名:wang 性別:man 年齡:21 Print Student info: 學號 姓名 性別 年齡 2017211758 wang man 21