由于c++的操作符只支持基本数据类型和标准库中提供的类的操作,而对于用户自己定义的类,则需要通过operator关键字进行函数重载,以此来拓展运算符的功能。例如,我们对于两个整型数进行相加运算可以通过+运算符实现,但是如果我们想要对自己定义的类直接使用+运算符却不行,虽然我们可以通过函数的调用来弥补这一缺陷,但是更好的做法是重载运算符,使得可以像对c++内置类型运算一样对类进行运算。
重载的一些规则:
1 C++不允许用户自己定义新的运算符,只能对已有的 C++运算符进行重载。
2 不能重载的运算符有 作用域操作符:: 条件操作符?: 点操作符.
指向成员操作的指针操作符->* 预处理符号# sizeof
此外 =、()、[]、以及 ->操作符只能被类的成员函数重载。
3 重载不能改变运算符运算对象的个数。比如+需要两个参数,重载后也是一样的。
4 重载不能改变运算符的优先级别。
5 重载运算符的函数不能有默认的参数,否则就改变了运算符参数的个数。
6 重载的运算符必须和用户定义的自定义类型的对象一起使用,其参数至少应有一个是类对象(或类对象的引用)。
也就是说,参数不能全部是 C++的标准类型,以防止用户修改用于标准类型数据成员的运算符的性质。
7 运算符重载函数可以是类的成员函数,也可以是类的友元函数,还可以是普通函数。
8 原则上使得重载后的运算符功能和原来保持一致,以免产生歧义和误用。
重载实例
单目运算符
单目运算符包括有自增自减运算符(++ ,–)、负号运算符(-)、逻辑非运算符
第一个例子,旨在区分前置运算符与后置运算符重载上的区别。
#include<iostream>
using namespace std;
//运算符重载,旨在对类与对象使用运算符,最常用的方式是使用成员函数
class Counter
{
public:
Counter();
~Counter() {}
int getValue() const {return value;}
void setValue(int x) {value=x;}
void increment() {++value;}//普通成员函数,实现成员变量自加
const Counter& operator++();//用于运算符重载,关键字operator,重载符前缀++,返回值类型const Counter&
const Counter operator++(int);//后缀++,用参数int区分
private:
int value;
} ;
Counter::Counter():
value(0)//赋初值为0
{}
const Counter& Counter::operator++()
{
++value; //功能:实现成员变量自增
return *this; //返回当前对象
}
const Counter Counter::operator++(int)
{
Counter temp(*this);
++value;
return temp;//临时对象不能按引用传递回去
}
int main()
{
Counter c;
cout<<"this value of c is "<<c.getValue()<<endl;
c.increment();
cout<<"this value of c is "<<c.getValue()<<endl;
++c;//运算符重载,对对象使用
cout<<"this value of c is "<<c.getValue()<<endl;
c++;
cout<<"this value of c is "<<c.getValue()<<endl;
Counter a=++c;
cout<<"this value of a is "<< a.getValue()<<endl;
cout<<"and c is "<<c.getValue()<<endl;
++a;
cout<<"this value of a is "<< a.getValue()<<endl;
cout<<"and c is "<<c.getValue()<<endl;
++c;
cout<<"this value of a is "<< a.getValue()<<endl;
cout<<"and c is "<<c.getValue()<<endl;
return 0;
}
运行结果:
this value of c is 0
this value of c is 1
this value of c is 2
this value of c is 3
this value of a is 4
and c is 4
this value of a is 5
and c is 4
this value of a is 5
and c is 5
重载单目运算符一般模型为: 返回值类型 类名::operator重载的运算符();
双目运算符
常用的双目运算符包括很多。
首先,有加(+)、减(-)、乘(*)、除(/)、取余(%)。
以加法为例,说明其重载方法。
#include<iostream>
//重载加法运算符,双目运算符
class Counter
{
public:
Counter();
Counter(int intitialValue);
~Counter() {}
int getValue() const {return value;}
void setValue(int x) {value = x;}
Counter operator+(const Counter&);
private:
int value;
};
Counter::Counter():
value(0)
{}
Counter::Counter(int initialValue):
value(initialValue)
{}
Counter Counter::operator+(const Counter &rhs)
{
return Counter(value+rhs.getValue());
}
int main()
{
Counter alpha(4),beta(13),gamma;
gamma=alpha+beta; //编译器解释为 gamma=alpha.operator+(beta);
std::cout<<"alpha = "<<alpha.getValue()<<std::endl;
std::cout<<"beta = "<<beta.getValue()<<std::endl;
std::cout<<"gamma = "<<gamma.getValue()<<std::endl;
return 0;
}
运行结果:
alpha = 4
beta = 13
gamma = 17
重载二元运算符时,一般模型为:返回值类型 类名::operator运算符名称(另一个类或变量的引用);
以加法为例,编译器在工作时会将gamma=alpha+beta; 解释为 gamma=alpha.operator+(beta);
**其次,可以重载关系运算符<、>、==、>=、<=。**以此来比较类的大小关系。
#include<iostream>
using namespace std;
class Data
{
public:
Data():value(0) {}
Data(int newValue):value(newValue){}
~Data(){}
void setValue(int newValue) {value=newValue;}
int getValue()const{return value;}
bool operator<(Data&);
bool operator==(Data&);
private:
int value;
};
bool Data::operator<(Data& rhs)
{
if(value<rhs.value) return true;
else return false;
}
bool Data::operator==(Data& rhs)
{
if(value==rhs.value) return true;
else return false;
}
int main()
{
Data a(5),b(10);
bool dayu,dengyu;
dayu=a<b;
cout<<"a<b:"<<dayu<<endl;
dayu=b<a;
cout<<"a>b:"<<dayu<<endl;
dengyu=a==b;
cout<<"a!=b:"<<dengyu<<endl;
a.setValue(10);
dengyu=a==b;
cout<<"a==b:"<<dengyu<<endl;
return 0;
}
运行结果:
a<b:1
a>b:0
a!=b:0
a==b:1
赋值运算符
就像其他运算符一样,您可以重载赋值运算符( = ),用于创建一个对象,比如拷贝构造函数。
#include<iostream>
//编译器提供了默认的赋值重载运算函数,也可自定义
class Tricycle
{
public:
Tricycle();
~Tricycle();
int getSpeed() const {return *speed;}
void setSpeed(int newSpeed) {*speed=newSpeed;}
Tricycle operator=(const Tricycle&); //双目运算符重载
private:
int *speed;
} ;
//构造函数
Tricycle::Tricycle()
{
speed=new int;
*speed=5;
}
//关于赋值运算符的重载的一般操作
Tricycle Tricycle::operator=(const Tricycle& rhs)//默认的赋值重载可能导致内存泄露
{
if(this==&rhs) //通过校验地址来判断是否相同
return *this; //如果赋值运算符右边与左边相同,则返回原对象
delete speed; //避免内存泄露,释放原堆内内存
speed=new int; //重新分配堆内内存
*speed=rhs.getSpeed(); //重新赋值
return *this; //返回这个对象
}
int main()
{
Tricycle wichita;
std::cout<<"Wichita's speed: "<<wichita.getSpeed()<<std::endl;
std::cout<<"Settting Wichita's speed to 6 "<<std::endl;
wichita.setSpeed(6);
Tricycle dallas;
std::cout<<"Dallas's speed: "<<dallas.getSpeed()<<std::endl;
std::cout<<"copying dallas to dallas"<<std::endl;
wichita=dallas;
std::cout<<"Dallas's speed: "<<dallas.getSpeed()<<std::endl;
std::cout<<"Wichita's speed: "<<wichita.getSpeed()<<std::endl;
return 0;
}
运行结果:
Wichita’s speed: 5
Settting Wichita’s speed to 6
Dallas’s speed: 5
copying dallas to dallas
Dallas’s speed: 5
Wichita’s speed: 5
.
转换运算符
通过构造函数实现c++内置类型转化成对象的功能。
#include<iostream>
using namespace std;
class Counter
{
public:
Counter():value(0){}
~Counter(){}
Counter(int newValue);
int getValue() const {return value;}
void setValue(int newValue){value=newValue;}
private:
int value;
};
Counter::Counter(int newValue):
value(newValue)
{
//通过构造函数来实现转换运算符的功能
//该函数调用时可以将整型赋给对象
}
int main()
{
int beta=5;
Counter alpha=beta;//实现转换
cout<<"alpha:"<<alpha.getValue()<<endl;
return 0;
}
输出:alpha=5
int()运算符重载
#include<iostream>
using namespace std;
class Number
{
public:
Number();
Number(int initialValue);
~Number() { }
int getValue() const {return value;}
void setValue(int newValue) {value=newValue;}
operator unsigned int();//重载int()运算符
private:
int value;
};
Number::Number():
value(0)
{
}
Number::Number(int initialValue):
value(initialValue)
{
}
Number::operator unsigned int()
{
return value;
}
int main()
{
Number object(10);
int number;
number=object;
cout<<number<<endl;
return 0;
}
输出 10
函数调用运算符 () 重载
函数调用运算符 () 可以被重载用于类的对象。当重载 () 时,您不是创造了一种新的调用函数的方式,相反地,这是创建一个可以传递任意数目参数的运算符函数。
#include<iostream>
using namespace std;
class Number
{
public:
Number():value(0){}
Number(int newValue):value(newValue){}
~Number(){}
int getValue() const {return value;}
void setValue(int newValue) {value=newValue;}
Number operator()(int a,int b,int c)
{
Number temp;
temp.value=a*b*c;
return temp;
}
private:
int value;
};
int main()
{
Number One(10);
Number Two=One(1,2,3);
cout<<"Two's value is:"<<Two.getValue()<<endl;
return 0;
}
输出结果:Two’s value is:6
下标运算符 [] 重载
下标操作符 [] 通常用于访问数组元素。重载该运算符用于增强操作 C++ 数组的功能。
#include<iostream>
using namespace std;
class Array
{
public:
Array(int newSize);
~Array();
int& operator[](int i);
private:
int* p;
int size;
};
Array::Array(int newSize):
size(newSize)
{
p=new int[size];
for(int i=0;i<size;i++)
*(p+i)=i;
}
Array::~Array()
{
delete [] p;
}
int& Array::operator[](int i)
{
if(i>=size||i<0)
{
cout<<"下标错误"<<endl;
exit(1);
}
return *(p+i);
}
int main()
{
Array a(3);
cout<<a[0]<<"\t"<<a[1]<<"\t"<<a[2];
return 0;
}
输出 0 1 2
输入/输出运算符
C++ 能够使用流提取运算符 >> 和流插入运算符 << 来输入和输出内置的数据类型。您可以重载流提取运算符和流插入运算符来操作对象等用户自定义的数据类型。
在这里,有一点很重要,我们需要把运算符重载函数声明为类的友元函数,这样我们就能不用创建对象而直接调用函数。
对“<<”和“>>”重载的函数形式如下:
istream & operator >> (istream &, 自定义类 &);
ostream & operator << (ostream &, 自定义类 &);
//在类中声明友元函数可以写成这样
friend std::ostream& operator<<(std::ostream& stream,String& newString);
//函数具体实现类似如下:
std::ostream& operator<<(std::ostream& stream,String& newString)
{
stream<<newString.getString();
return stream;
}
std::istream& operator >> (std::istream& input,Complex& c) //定义重载运算符“>>”
{
cout<<"input real part and imaginary part of complex number:"<<endl;
input>>c.real>>c.imag; //real和imag为类Complex的两个成员变量
return input;
}