運算符重載
什麼式運算符重載呢?在c++裏對於兩個整型變量a和b,有a+b,含義是將a+b加起來,對於對象呢,我們可以重載‘+’的含義,從而可以使對象a,b,相加,比如A類是描述複數的類,a,b是A類的兩個對象,我們可以使用a+b來求出兩個複數的相加結果。
簡單來講運算符重載就是 程序員可以自己 定義 自定義類型的數據結構的加減等操作。
不能重載的運算符:"." 、".*"、"::"、"?:"
重載只有運算符的優先級和結核性都不會改變。
雙目運算符重載爲成員函數
語法:
函數類型 operator 運算符(形參)
{
}
參數個數=原操操作數 -1(具體看下面例子)
規則:
如果要重載B爲類成員函數,使之能夠實現表達式oprd1 B oprd2其中oprd1爲A類對象,則B應被重載爲A類的成員對象,形參類型因應該是oprd2所屬類型
經過重載後,表達式 oprd1 B oprd2 相當於oprd1.operator B(oprd2);
舉個栗子:實現複數類加減法運算重載爲成員函數
#include<iostream>
using namespace std;
class Complex
{
public:
Complex(double r=0.0,double i=0.0):real(r),imag(i){}
Complex operator + (const Complex &c2) const;
Complex operator - (const Complex &c2) const;
void display() const;
private:
double real;//實數部分
double imag;//虛數部分
};
Complex Complex::operator + (const Complex &c2) const
//創建一個臨時無名對象作爲返回值
{
return Complex(real+c2.real,imag+c2.imag);
}
Complex Complex::operator - (const Complex &c2) const
//創建一個臨時無名對象作爲返回值
{
return Complex(real-c2.real,imag-c2.imag);
}
void Complex::display()const
{
cout<<real<<","<<imag<<endl;
}
int main()
{
Complex c1(5,4),c2(2,10),c3;
cout<<"c1 = ";c1.display();
cout<<"c2 = ";c2.display();
c3=c1-c2;
cout<<"c3 = c1 - c2 = ";c3.display();
c3=c1+c2;
cout<<"c3 = c1 + c2 = ";c3.display();
return 0;
}
單目運算符重載
前置單目運算符 重載規則
如果用重載U爲類成員函數,是指能夠實現表達式 U oprd ,其中oprd爲A類對象,則U應被承載爲A類的成員函數,五形參。
經重載後,表達式U oprd相當於 oprd.operator U();
後置單目運算符 ++和--重載規則
如果要重載 ++或--爲類的成員函數,實現oprd++ 或 oprd--,則++或--應被重載爲A類的成員函數且應具有一個int類型的形參
這個int形參只是起到區分是 前置++後置++的作用。
前置++和後置++的例子
class A
{
public:
A(int x=0);
A& operator ++();//前置單目運算符重載
A operator ++(int);//後置單目運算符重載
private:
int x;
};
A & A::operator++()
{
x++;
return *this;
}
A A::operator++(int)
{
A old=*this;
++(*this);//調用前置++重載函數
return old;
}
如果是全局的函數,雙目運算符需要兩個參數,用來傳運算符左右兩個算子
Integer operator +(const Integer &c,const Integer &b)
{
return (c.n+b.n);
}
運算符重載——類型轉換
C++會自動轉換類型,比如下面的f函數,它的參數是Two類型的,但是主函數裏給了它一個One類型的,然而Two類裏有一個構造函數可以把One類型轉換爲Two類型,程序就會自動去調用這個構造函數去自動轉換,如果不想這樣的話,可以在那個構造函數前面加一個 explicit
class One
{
public;
One(){}
};
class Two
{
public:
Two(const One&){}
};
void f(Two)
{
}
int main()
{
One one;
f(one);
}
#include<iostream>
using namespace std;
class Integer
{
private:
int n;
public:
Integer(int x=0):n(x){}
Integer operator +(const Integer &c)
{
return (c.n+n);
}
};
int main()
{
Integer x,y,z;
z=x+y;
z=x+3;
z=3+y;
}
z=x+3是合法的,編譯器在遇到加法後,會看加號前面那個變量是什麼類型,再來確定是系統的加法還是重載的加法,這裏由於加法是重載的加法,但是3是整型變量,程序會自動調用Integer類的構造函數,創造一個臨時對象,來實現這個運算表達式.
如果將重載函數改一下,改成全局函數就可以實現z=3+y了
class Integer
{
private:
int n;
public:
Integer(int x=0):n(x){}
friend Integer operator +(const Integer &c,const Integer &d)
{
return (c.n+d.n);
}
};
重載函數模型
int是來區分前置還是後置,不會起作用
prefix++是前置++,postfix是後置++
運算符重載——賦值
#include<iostream>
using namespace std;
class A
{
public:
A(){}
};
class B
{
public:
B(int){}
B(const A&){}
};
int main()
{
B b = 1;
A a;
B c = a;//調用拷貝構造函數
c=a;//先把a變成一個B類的對象,然後把它賦值給c,調用了系統提供的默認賦值操作
return 0;
}
這個默認的賦值操作,在操作有指針成員變量的對象時候也會發生拷貝構造函數那樣的問題,這時候我們要手動重載賦值運算符
模板
T& T::operator=(const T &rhs)
{
if(this !=&rhs)
{
//清空指針所指內存,分配內存指向被複制的那個對象。
}
return *this;
}
爲什麼要考慮是不是自己給自己賦值呢?
看下列代碼
class A
{
char *p;
A& operator=(const A&that)
{
delete p;
p=new[strlen(that.p)+1];
strcpy(p,p.that.p);
return *this;
}
};
如果不考慮是不是自己給自己賦值,那麼上述代碼中delete p 這條代碼把自己指針free了,下面的strlen和strcpy就出錯了