C++運算子過載的實現
說起CPP的運算子過載,總是讓人有些不理解,如果這是函式這個函式長得也太怪了吧,YES ,就是一種函式,只是這種函式時我們在給CPP所給的運算子功能上面新增功能時候使用的一種函式,注意不能減少CPP已經存在的的運算子的功能。
定義一個過載運算子就像定義一個函式,只是該函式的名字是[email protected],這裡@代表運算子。函式引數表中引數的個數取決於兩個因素:
1) 運算子是一元的(一個引數)還是二元的(兩個引數)。
2) 運算子被定義為全域性函式(友員函式,普通函式)(對於一元是一個引數,對於二元是兩個引數)還是成員函式(對於一元沒有引數,對於二元是一個引數 — 物件變為左側引數)。
因為我們一般運算子過載都是為了資料的訪問,如果資料屬於公有的,那麼就可以將運算子過載為普通函式,一般作為CPP的封裝性質,一般就將運算子過載為成員函式和友員函式。那麼問題來了,到底什麼時候過載為友員函式,什麼時候過載為成員函式
在多數情況下,將運算子過載為類的成員函式和類的友元函式都是可以的。而在某種情況下,程式設計師沒得選擇,只能過載為類成員。
但成員函式運算子與友元函式運算子也具有各自的一些特點:
(1) 一般情況下,單目運算子最好過載為類的成員函式;雙目運算子則最好過載為類的友元函式。
(2) 以下一些雙目運算子不能過載為類的友元函式:=、()、[]、->。必須將他們定義為成員,定義為非成員函式將在編譯的時候出現錯誤。
(3) 型別轉換函式只能定義為一個類的成員函式而不能定義為類的友元函式。
(4) 若一個運算子的操作需要修改物件的狀態或者與給定型別緊密聯絡的一些操作符,選擇過載為成員函式較好。如自增,自減,解引用。
(5) 若運算子所需的運算元(尤其是第一個運算元)希望有隱式型別轉換,則只能選用友元函式。
(6) 當運算子函式是一個成員函式時,最左邊的運算元(或者只有最左邊的運算元)必須是運算子類的一個類物件(或者是對該類物件的引用)。如果左邊的運算元必須是一個不同類的物件,或者是一個內部 型別的物件,該運算子函式必須作為一個友元函式來實現(插入,提取 運算子的過載)。
(7) 當需要過載運算子具有可交換性時,即對稱的操作符,如關係運算符,相等操作符,算數運算子,位操作符,則選擇過載為友元函式。
雖然可以過載幾乎所有 C中可用的運算子,但使用它們是相當受限制的(具體的限制參看這篇文章)。特別地,不能結合C中當前沒有意義的運算子(例如 * *求冪),不能改變運算子的優先順序,不能改變運算子的引數個數。這樣限制有意義—所有這些行為產生的運算子只會造成意思混淆而不是使之清楚。
當然下面是所謂的“常用”的運算子的過載。他們的過載完全基於上邊的這些規則,如果既可以過載為友員函式,也可以過載為成員函式,我會給出兩種方式:
以下是可以過載的運算子
雙目算術運算子 + (加),-(減),*(乘),/(除),% (取模)
關係運算符 ==(等於),!= (不等於),< (小於),> (大於>,<=(小於等於),>=(大於等於)
邏輯運算子 ||(邏輯或),&&(邏輯與),!(邏輯非)
單目運算子 + (正),-(負),*(指標),&(取地址)
自增自減運算子 ++(自增),--(自減)
位運算子 | (按位或),& (按位與),~(按位取反),^(按位異或),,<< (左移),>>(右移)
賦值運算子 =, +=, -=, *=, /= , % = , &=, |=, ^=, <<=, >>=
空間申請與釋放 new, delete, new[ ] , delete[]
其他運算子 ()(函式呼叫),->(成員訪問),->*(成員指標訪問),,(逗號),[](下標)
不能過載的運算子只有5個:
. (成員訪問運算子)
.* (成員指標訪問運算子)
:: (域運算子)
sizeof (長度運算子)
?: (條件運算子)
前兩個運算子不能過載是為了保證訪問成員的功能不能被改變,域運算子和sizeof 運算子的運算物件是型別而不是變數或一般表示式,不具備過載的特徵,C++不允許過載三目運算子。
運算子分為單目雙目和三目:
運算所需變數為一個的運算子叫單目運算子,又叫一元運算子.
邏輯非運算子【!】、按位取反運算子【~】、自增自減運算子【++, --】、負號運算子【-】、型別轉換運算子【(型別)】、指標運算子和取地址運算子【*和&】、長度運算子【sizeof】
運算所需變數為兩個的運算子叫做雙目運算子,例如+,-,*,/,%,<,>,>=,<=,==,!=,<<,>>,&,^,|,&&,||,=
運算所需變數為三個的運算子叫做三目運算子,只有條件表示式【?:】
/*/**********************************************************************
* * Copyright (c)2015,WK Studio
* * Filename: String.h
* * Compiler: GCC vs2013
* * Author:WK
* * Time: 2015 16 6
* **********************************************************************/
#include<iostream>
#include<assert.h>
using namespace std;
class A
{
public:
A(int i = 0):m_data(i)
{
cout << "Create the Object! " << this << " \n";
}
A(const A &a);
~A()
{
//free()對於含有指標資料的物件
cout << "Destructor the Object!" << this << " \n";
}
A& operator=(const A &a);//可以返回引用也可以返回物件,返回引用更好偶
//+ - * / % (物件之間的操作都是對各自的資料進行操作)
A operator+(const A &a);//返回物件足以實現連續的+
friend A operator+(const A &a, const A &b);
//+= -= *= /= %=
A& operator+=(const A &a);//可以返回引用也可以返回物件,返回引用更好偶
friend A operator+=( A &a,const A &b);
//單目運算子過載(正,負,解引用,取地址)
//+號雷同
A& operator - ();
friend A operator -(A &a);
//取地址&
A* operator & ();//返回物件地址用物件指標接受
//friend A * operator&(A &a);
//解引用
A& operator * ();
friend A& operator* (A &a);
//條件運算子 == != < > >= <= 雷同
bool operator == (const A &a);
friend bool operator == (const A &a, const A &b);
//邏輯運算子過載(&& ||)
bool operator &&(const A & a);
friend bool operator && (const A &a, const A&b);
bool operator !();
friend bool operator !(A &a);
//自增減運算子過載
A& operator ++ ();//前置++
//friend A& operator ++ (A &a);//前置++
A operator ++ (int);//後置++
//A& operator --();//前置-- 雷同
//A operator -- (int);//後置--
//只能用友元函式過載
friend inline ostream &operator << (ostream&, A&);//提取運算負的過載
friend inline istream &operator >> (istream&, A&);//插入運算子的過載
//位運算子過載
A operator | (const A&);
friend A operator | (const A &a, const A &b);
//A operator & (const A&);
//A operator ^ (const A&);
A operator << (int i);
friend A operator << (A &a,int i);
//A operator >> (int i);
A operator ~ ();
friend A operator ~(A &a);
int& operator () ();
private:
int m_data;
};
int main()
{
A s1(4);
A s2(5);
A s3 = s1 + s2;
A s4;
s4= s1 + s2 + s3;
cout << s1() << "\n";
s1() = 5;
cout << s1() << "\n";
A s17 = s1.operator~();//s17 = ~s1;
A s18 = operator~(s1);//呼叫友員函式
A s15 = s1.operator<<(2);//s15= s1<<2;因為<<存在多個過載函式,無法鑑別,所以可以刪除幾個在使用
A s16 = operator<<(s1, 2);//呼叫友員函式
A s14= s1 | s2;
A s12 = ++s1;
s4 = s1.operator+(s2);
s4 = operator+(s1, s2);
A s6;
//s6 += s1;//當+=的兩個過載即成員函式過載和友員函式過載都在時候就會出現不知道呼叫那一個,用時候刪掉一個
s6.operator+=(s1);
s6 = operator+=(s6, s1);
A s5 = s1 = s2 = 999;//從右至左,先是用99生成一個臨時物件,在呼叫兩次賦值函式,在呼叫一次拷貝構造
A s7(-1);
A s8 = s7.operator-();//-s7;當-的兩個過載即成員函式過載和友員函式過載都在時候就會出現不知道呼叫那一個,用時候刪掉一個
A s9=operator-(s7);
operator-(s7);//友員函式呼叫
//A *p = &s1;//當&的兩個過載即成員函式過載和友員函式過載都在時候就會出現不知道呼叫那一個,用時候刪掉一個
A *p = s1.operator &();
//A *p1 = operator&(s1);//友員函式呼叫
A s10 = p->operator*();
A s11 = operator*(s1);
cout << (s10 == s11) << "\n";
cout << (s10 && s11) << "\n";
cout << s10.operator!() << "\n";
cout << operator!(s10)<<"\n";
A s13;
cin >>s13;
cout<<s13;
getchar();
return 0;
}
//拷貝構造(對於這種只有的整型的物件可以使用預設的拷貝構造,但是對於物件的資料是指標或者其他就要重新定義拷貝構造)
A:: A(const A &a)
{
cout << "Copy the Object! "<<this<<" "<<&a<<" \n";
m_data = a.m_data;
}
A A:: operator+(const A &a)
{
cout << "A:: + overloadFun the Object! " << this<<" " << &a << " \n";
return A(this->m_data+ a.m_data);
}
A operator+(const A &a, const A &b)
{
cout << "Friend + overloadFun the Object! "<<&a<<" "<<&b<<" \n";
return A(a.m_data + b.m_data);
}
A& A:: operator=(const A &a)
{
cout << "(Only)A:: = overloadFun the Object! " << this << " " << &a << " \n";
if (this != &a)
{
//free()對於資料是指標要先進行記憶體的釋放
this->m_data = a.m_data;
}
return *this;
}
A& A:: operator+=(const A &a)
{
cout << "+= overloadFun the Object! \n";
this->m_data +=a.m_data;//*this +=a.data;引起不停的呼叫+=過載函式無限迴圈,vs中會將後邊的資料生成一個臨時物件進行相加,vc6.0會報錯必須*this +=(A)a.data;*this= *this + a.data;也是對的
return *this;
}
A operator+=(A &a, const A &b)
{
cout << "Friend += overloadFun the Object! \n";
a.m_data +=b.m_data;
return A(a.m_data);
}
A& A:: operator - ()
{
cout << "- overloadFun the Object! \n";
this->m_data= -this->m_data;
return *this;
}
A operator -(A &a)
{
cout << "Friend - overloadFun the Object! \n";
a.m_data = -a.m_data;
return A(a.m_data);
}
A* A:: operator & ()
{
cout << "& overloadFun the Object! \n";
return this;
}
/*
A * operator&(A &a)
{
cout << "& Friend overloadFun the Object! \n";
return &a;//成員函式與友員函式不能同時存在,否則這個&就會呼叫成員函式過載的&
}*/
A& A:: operator * ()
{
cout << "* overloadFun the Object! \n";
return *this;
}
A& operator * (A &a)
{
cout << "*v Friend overloadFun the Object! \n";
return a;
}
bool A:: operator == (const A &a)
{
cout << "== overloadFun the Object! \n";
if (this->m_data == a.m_data)
{
return true;
}
return false;
}
bool operator == (const A &a,const A &b)
{
cout << "== Friend overloadFun the Object! \n";
if (a.m_data == b.m_data)
{
return true;
}
return false;
}
bool A:: operator && (const A &a)
{
cout << "&& overloadFun the Object! \n";
if (this->m_data && a.m_data)
{
return true;
}
return false;
}
bool operator &&(const A &a, const A & b)
{
cout << "&& Friend overloadFun the Object! \n";
if (a.m_data && b.m_data)
{
return true;
}
return false;
}
bool A:: operator !()
{
cout << "! overloadFun the Object! \n";
if (this->m_data == 0)
{
return true;
}
return false;
}
bool operator !(A &a)
{
cout << "! Friend overloadFun the Object! \n";
if (a.m_data == 0)
{
return true;
}
return false;
}
A& A::operator ++ ()
{
++m_data;
return *this;
}
/*
A operator++ (A &a)//前置++
{
return A(++a.m_data);
}*/
A A::operator ++ (int)//後置++
{
return A(m_data++);
}
ostream &operator << (ostream &out, A &a)//提取運算負的過載
{
out << a.m_data;
return out;
}
istream &operator >> (istream &in, A &a)//插入運算子的過載
{
int data;
in >> data;
a.m_data = data;
return in;
}
A A::operator | (const A &a)
{
return A(this->m_data | a.m_data);
}
A operator | (const A &a, const A &b)
{
return A(a.m_data | b.m_data);
}
A A:: operator << (int i)
{
return A(this->m_data << i);
}
A operator << (A &a, int i)
{
return A(a.m_data<<i);
}
A A::operator ~ ()
{
return A(~this->m_data);
}
A operator ~ (A &a)
{
return A(~a.m_data);
}
int& A::operator () ()
{
return this->m_data;
}
//型別轉換符過載
/**********************************************************************
* Copyright (c)2015,WK Studios
* Filename:
* Compiler: GCC VC6.0 win32
* Author:WK
* Time: 2015 6 6
************************************************************************/
#include<iostream>
using namespace std;
class S
{
public:
//型別轉換符
operator int()
{
return m_data;
}
//operator char* () const;
//operator const char() const;
//operator short int() const;
//operator long long() const;
S (int n):m_data(n)
{
cout<<"Create the object!"<<this<<"\n";
}
~S()
{
cout<<"Free the object!"<<this<<"\n";
}
S operator =(S &a);
S (S &a);
private:
int m_data;
};
int main()
{
S s1(5);
int a=s1;
return 0;
}
S S::operator =(S &a)
{
if(this!=&a)
{
m_data=a.m_data;
}
cout<<"= Operator "<<this<<endl;
return S(*this);
}
S::S(S &a)
{
cout<<"Copy "<<this<<endl;
m_data=a.m_data;
}
#include <iostream>
using namespace std;
//補充前置++和後置++的過載
class A
{
private:
int m_data;
public:
A(int a=0):m_data(a)
{
}
A operator++()
{
return A(++m_data);
}
A operator++(int)
{
return A(m_data++);
}
friend A operator++(A &a)
{
return A(++a.m_data);
}
friend A operator++(A &a,int)
{
return A(a.m_data++);
}
void show()
{
cout<<m_data<<"\n";
}
};
int main()
{
A a(1);
a.operator++(); //++a;前置++的成員函式呼叫
a.show();
a.operator++(0);//a++;後置++的成員函式呼叫
a.show();
operator++(a);//++a;前置++的友員函式呼叫
a.show();
operator++(a,0);//a++;後置++的int 只是用來標識與前置++的區別,int引數一般預設傳遞值0
a.show();
}
#include <iostream>
using namespace std;
//增加()運算子的過載
class Matrix
{
private:
int *m;
int row ,col;
public:
Matrix(int =0,int =0);
int& operator()(int,int);
};
int main()
{
Matrix aM(10,10);
cout<<aM(3,4)<<"\n";
aM(3,4)=35;
cout<<aM(3,4)<<"\n";
return 0;
}
Matrix::Matrix(int row,int col )
{
this->row=row;
this->col=col;
m=new int [col*row];
for(int i=0;i<col*row;++i)
{
*(m+i)=i;
}
}
int& Matrix::operator()(int r,int c)
{
return(*(m+(r*col)+c));
}
#include <iostream>
using namespace std;
//實現給某一天加上天數,過載運算子+的應用
class date
{
public:
date(int y=1970,int m=1,int d=1):year(y),month(m),day(d)
{
}
void show()
{
cout<<year<<": "<<month<<": "<<day<<" \n";
}
date& operator+(int );
protected:
private:
int year;
int month;
int day;
};
static days[2][12]={{31,28,31,30,31,30,31,31,30,31,30,31},
{31,29,31,30,31,30,31,31,30,31,30,31}};
int isleap(int y)
{
if((y%4==0 && y%100!=0) || (y%400==0))
return 1;
else
return 0;
}
int main()
{ date s1(2015,1,1);
s1.show();
date s2;
s2=s1+365;
s2.show();
return 0;
}
date& date:: operator+(int n)
{
int leap=isleap(this->year);
n+=this->day;
while(n>days[leap][this->month-1])
{
n-=days[leap][this->month-1];
if(++this->month==13)
{
this->month=1;
this->year++;
leap=isleap(this->year);
}
}
this->day=n;
return *this;
}
對於->*的過載和()的過載
class sim
{
public:
int f(int i)const
{
return 1;
}
};
int (sim::*fp)(int)const;
void main()
{
sim *s;
sim s1;
fp = sim::f;
//&sim::f;
cout<<(s->*fp)(3)<<endl;//並沒有呼叫->*的過載
cout<<(s.*fp)(3)<<endl;
}
#include <iostream>
using namespace std;
class Dog
{
public:
int run(int i)const
{
cout<<"run\n";
return i;
}
int eat(int i)const
{
cout<<"eat\n";
return i;
}
int sleep(int i)const
{
cout<<"sleep\n";
return i;
}
typedef int(Dog::*Fun) (int)const;//這裡的函式函式返回值可以使用模板進行擴充套件通用
class FunObje
{
public:
FunObje(Dog* p,Fun pm):ptr(p),pmen(pm)
{
cout<<"FunObje()\n";
}
int operator()(int i)const
{
cout<<"operator()\n";
return (ptr->*pmen)(i);
}
private:
Dog *ptr;
Fun pmen;
};
FunObje operator->*(Fun pmf)//返回一個無名臨時物件
{
cout<<"operator->*()\n";
return FunObje(this,pmf);
}
};
void main()
{
Dog w;
Dog::Fun pmf = Dog::run;
// &Dog::run;
cout<<(w->*pmf)(1)<<endl;//呼叫->*的過載
pmf = Dog::sleep;
cout<<(w->*pmf)(2)<<endl;
pmf = Dog::eat;
cout<<(w->*pmf)(3)<<endl;
}