首先为什么要对运算符进行重载?因为C++内置的运算符只能作用于一些基本数据类型,而对类和结构体这种自定义数据类型是不管用的。所以这时我们需要对运算符进行重新定义满足一定的运算规则。
运算符重载的三种形式
1.以普通的函数进行重载
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
class Complex
{
private:
int _real;
int _image;
public:
Complex(int real=0 ,int image=0);
~Complex();
int getReal()const;
int getImage()const;
void print();
};
Complex::Complex(int real ,int image)
:_real(real)
,_image(image)
{
cout<<"complex()"<<endl;
}
Complex::~Complex()
{
cout<<"~Complex()"<<endl;
}
int Complex::getImage() const
{
return _image;
}
int Complex::getReal() const
{
return _real;
}
Complex operator+(const Complex& rhs1,const Complex& rhs2)
{
return Complex(rhs1.getReal()+rhs2.getReal(),rhs1.getImage()+rhs2.getImage());
}
void Complex::print()
{
cout<<_real<<" + "<<_image<<"i"<<endl;
}
int main()
{
Complex a(1,2);
Complex b(2,3);
Complex c=a+b;
c.print();
return 0;
}
有几个问题需要注意:
1.在类外调用private成员变量需要写个public接口函数。
2.返回临时对象不能加&引用,此时调用两次拷贝构造函数,将临时对象返回给operator+()时满足拷贝函数调用时机3,而将operator+()函数赋值给c又满足拷贝构造函数调用时机1。
3.const 对象只能调用const成员函数,因此Complex operator+(const Complex& rhs1,const Complex& rhs2)中的rhs1和rhs2两个对象只能调用const的成员函数,所以要将getReal()和getImage()设置成const。
4.当构造函数的定义和声明分开时,在设置默认参数时要注意只需要在一个地方设置默认参数,要么在声明出设置默认参数,要么在定义出设置默认参数。
2.以成员函数进行重载
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
class Complex
{
private:
int _real;
int _image;
public:
Complex(int real, int image);
~Complex();
//函数中隐藏了this指针,+参数只能有两个
Complex operator+(const Complex& rhs2);
void print() const
{
cout<<_real<<" + "<<_image<<"i"<<endl;
}
};
Complex::Complex(int real=0, int image=0)
: _real(real), _image(image)
{
cout<<"Complex()"<<endl;
}
Complex::~Complex()
{
cout<<"~Complex()"<<endl;
}
//
Complex Complex::operator+(const Complex& rhs2)
{
Complex temp;
temp._real=this->_real+rhs2._real;
temp._image=this->_image+rhs2._image;
return temp;
}
int main()
{
Complex a(1,2);
Complex b(2,3);
Complex c=a+b;
c.print();
}
要注意的是:
在定义成员函数的运算符重载时,在非静态成员函数的参数第一个位置默认有一个this变量。
因此我们只需要设置一个Complex形参。
3.以友元函数进行重载
#include <iostream>
using std::cout;
using std::endl;
class Complex
{
private:
int _real;
int _image;
public:
Complex(int real,int image);
~Complex();
friend Complex operator+(const Complex& rhs1,const Complex& rhs2);
void print() const;
};
Complex::Complex(int real=0,int image=0)
:_real(real)
,_image(image)
{
cout<<"Complex()"<<endl;
}
Complex::~Complex()
{
cout<<"~Complex()"<<endl;
}
Complex operator+(const Complex& rhs1,const Complex& rhs2)
{
return Complex(rhs1._real+rhs2._real,rhs1._image+rhs2._image);
}
void Complex::print() const
{
cout<<_real<<" + "<<_image<<"i"<<endl;
}
int main()
{
Complex a(2,3);
Complex b(3,4);
Complex c=a+b;
c.print();
return 0;
}
可以看出在运算符重载时用友元函数比其他两种方法更加清晰简单。
在举个(a++)和(++a)的例子
#include <iostream>
using std::cout;
using std::endl;
class Complex
{
private:
int _real;
int _image;
public:
Complex(int real,int image);
~Complex();
friend Complex operator+(const Complex& rhs1,const Complex& rhs2);
Complex& operator++();
Complex operator++(int);
void print() const;
};
Complex::Complex(int real=0,int image=0)
:_real(real)
,_image(image)
{
cout<<"Complex()"<<endl;
}
Complex::~Complex()
{
cout<<"~Complex()"<<endl;
}
Complex operator+(const Complex& rhs1,const Complex& rhs2)
{
return Complex(rhs1._real+rhs2._real,rhs1._image+rhs2._image);
}
void Complex::print() const
{
cout<<_real<<" + "<<_image<<"i"<<endl;
}
Complex& Complex::operator++()
{
++_real;
++_image;
return *this;
}
Complex Complex::operator++(int)
{
Complex tem=*this;
_real++;
_image++;
return tem;
}
int main()
{
Complex a(2,3);
Complex b(3,4);
cout<<"(a++).print() = ";
(a++).print();
cout<<endl<<endl;
cout<<"a.print() = ";
a.print();
cout<<endl<<endl;
cout<<"(++b).print() = ";
(++b).print();
return 0;
}
运算符重载的规则
1.为了防止用户对标准类型进行运算符重载,C++规定重载的运算符的操作对象必须至少有一个是自定义类型或枚举类型。
2.重载运算符之后,其优先级和结合性还是固定不变的。
3.重载逻辑运算符(&&,||)后,不再具备短路求值特性。
4.重载不会改变运算符的用法,如操作数的个数、操作数的位置,这些都不会改变。
5.不可重载的运算符 ( . :: ?: *. sizeof )