运算符重载形式
重载是c++的一大特性,不仅可以用于一般函数重载,还可以用于运算符重载,对于一些基本数据类型来说运算符可以直接拿来使用,所以运算符重载一般是应用于对象之间,而对象之间的运算符重载主要分为成员运算符重载和友元运算符重载两种形式。
成员运算符重载:表示在类内定义的这个与运算符相关的函数是属于类的成员函数。所以他可以直接由对象调用对于双目运算符他只需要一个参数(另外一个参数其实就是调用它的对象)
友元运算符重载:以友元函数的形式对对象进行运算符重载,所以对于双目运算符来说,它需要两个参数都写出来。
#include<iostream>
using namespace std;
class A
{
public:
A(int num);
A operator +(int num);
friend A operator+(int,const A&);
void show();
private:
int _num;
};
A::A(int num)
{
_num = num;
}
A A::operator +(int num)
{
cout << "成员运算符重载:" << endl;
A a(this->_num + num);
return a;
}
A operator+(int num, const A& a)
{
cout << "友元运算符重载:" << endl;
//因为是类A的友元函数所以可以访问类A对象的私有成员
A b(num + a._num);
return b;
}
void A::show()
{
cout << this->_num << endl;
}
int main()
{
A a(12);
a = a + 2;
a.show();
a = 2 + a;
a.show();
system("pause");
return 0;
}
可以看出:
对象在左边时调用的是成员运算符重载函数,而对象在右边时调用的是友元运算符重载函数,因为只有对象在左边时对象才可能访问自身的成员函数,对于双目运算符重载对象在运算符右边的情况则一定要使用有缘运算符重载才行。
运算符重载种类
一般运算符重载
//加号重载
A operator +(int num);
friend A operator+(int, const A&);
//减号重载
A operator -(int num);
friend A operator-(int, const A&);
//乘号重载
A operator *(int num);
friend A operator*(int, const A&);
//除号重载
A operator /(int num);
friend A operator/(int, const A&);
具体函数实现参照上面加号重载的实现!
逻辑运算符重载
bool operator || (const A&);
bool operator && (const A&);
bool operator ! ();
bool A::operator&&(const A& a)
{
bool ret=false;
if(a._num&&this->_num)
ret=true;
return ret;
}
bool A::operator||(const A& a)
{
bool ret=false;
if(a._num||this->_num)
ret=true;
return ret;
}
bool A::operator!()
{
bool ret=false;
if(!this->_num)
ret=true;
return ret;
}
这里的逻辑运算符的两个运算对象都是同一个类的对象所以只使用成员运算符重载即可,但如果两个运算对象是不同的类型则还需要使用友元运算符重载保证即使两个运算对象调换左右位置仍能正常达到运算符重载的效果。
流运算符重载
流运算符包括输入流和输出流。
流运算符重载的两个运算对象一个是输入缓冲区/输出缓冲区,另一个是要输入/输出的对象。而类的对象在流运算符的右边,不能通过访问成员函数的形式调用运算符重载函数,所以只能使用友元运算符重载的形式。
friend ostream& operator << (ostream&, A&);
friend istream& operator >> (istream&, A&);
ostream& operator << (ostream& output, A& a)
{
output<<a._num;
return output;
}
istream& operator >> (istream& iutput, A& a)
{
input >> a._num;
return input;
}
赋值运算符重载
A& operator = (const A&);
A& operator += (const A&);
A& operator -= (const A&);
A& operator *= (const A&);
A& operator /= (const A&);
A& A::operator += (const const A& a)
{
this->_num=this->_num+a._num;
return *this;
}
因为是赋值运算符,所以在对对象赋值后还要返回对象的引用,这也是它与直接的四则运算符一个不同的地方(+,=,*,/只是返回一个临时对象!)。
关系运算符
关系运算的目的是为了判断俩个运算对象是不是满足某种关系,满足返回true,不满足返回false,所以关系运算符重载的返回值都为bool类型。
bool operator > (const A& );
bool operator < (const A& );
bool operator == (const A& );
bool operator >= (const A& );
bool operator <= (const A& );
bool A::operator >= (const A& a)
{ bool ret=false;
if(this->_num>a._num)
ret=true;
return ret;
}
//其它的类似
四则运算符重载和拷贝构造函数的配合
四则运算符重载函数返回的值是一个临时对象,在将这个返回值赋值给左值时根据左值的不同分为两种情况:
对象3=对象1+对象2;
这时返回值赋值给左值时会调用转换构造函数拿着这个返回值生成一个临时对象再将这个对象赋值给左值。
类名 对象名=对象1+对象2
这时返回值赋值给左值时,会直接调用拷贝构造函数,根据这个返回值生成新对象。
以上不论哪种情况都会调用拷贝构造函数,所以如果类内含有指针,对四则运算符进行重载时一定要对拷贝构造函数重载使其从浅拷贝变为深拷贝!
class A
{
public:
A();
A(char *);
~A();
A operator +(const A&);
A(const A&);
void show();
private:
char* _data;
int _len;
};
A::A()
{
_len = 0;
_data = nullptr;
}
A::A(char * str)
{
_len = strlen(str) + sizeof(char);
_data = new char[_len];
strcpy(_data, str);
}
A::~A()
{
if(_data)
delete[] _data;
}
A A::operator +(const A& a)
{
char ch[255];
strcpy(ch, _data);
strcat(ch, a._data);
A temp(ch);
return temp;
}
//深拷贝,为新生成对象内部指针成员变量重新分配空间。
A::A(const A& a)
{
this->_len = a._len;
_data = new char[_len];
strcpy(this->_data, a._data);
}
void A::show()
{
cout << this->_data << endl;
}
int main()
{
A a1("12");
A a2("34");
A a3= a1 + a2;
a1.show();
a2.show();
a3.show();
system("pause");
return 0;
}
运行结果:
这里要注意的是:第一种情况中不仅要对拷贝构造函数重载还要对’=‘进行重载为对象的指针变量重新分配控件,不然在最后一步对象之间赋值时仍然会出错!