C++操作符重载学习与使用-算数运算符、赋值、自增、输入输出操作符
操作符重载概念
class Complex
{
int real;
int img;
public:
Complex():real(0),img(0){};
Complex(int r,int i):real(r),img(i){};
}
Complex c1;
Complex c2 = Complex(1,2);
c1 + c2;
// 尝试进行 C1 + C2 的操作
程序运行报错,说明对于 c1
和 c2
来说,是无法直接进行算术运算符操作的,可以重定义或重载大部分 C++ 内置的运算符,这样就能使用自定义类型的运算符进行操作,这里将进行算术运算符的重载。
首先来看一个常规操作
Complex addNumber(Complex &p1)
{
Complex p3;
p3.real = this->real + p1.real;
p3.img = this->img + p1.img;
return p3;
}
Complex c3 = c1.addNumber(c2);
这种方式看起来可以实现,但是每次都需要调用函数去计算,如何进行化简呢?
Complex operator+(Complex &p1)
{
Complex p3;
p3.real = this->real + p1.real;
p3.img = this->img + p1.img;
return p3;
}
Complex c3 = c1 + c2;
// 等价于 Complex c3 = c1.operator+(c2);
以上就是算数运算符重载的实现方式,这种方式叫做成员函数重载,此外,还可以定义友元方式的重载。
首先在类中声明友元函数
friend Complex operator+(Complex &p1, Complex &p2);
由于友元是没有 this
指针的,所以要标明形参。
Complex operator+(Complex &p1, Complex &p2)
{
Complex p3;
p3.real = p1.real + p2.real;
p3.img = p1.img + p2.img;
return p3;
}
友元调用形式为:
Complex c3 = c1 + c2;
// 等价于 Complex c3 = operator+(c1, c2);
注意:对于不是一定需要 this
指针的一般定义为友元重载,会让调用更加方便。为什么这么说呢,看个例子,如果是 int k = a + b;
的形式,使用成员函数重载是没问题的,a
是一个对象可以调用 this
指针,但是如果是 int k = 1 + b;
,那么对成员是不可行的,而友元可行。
赋值操作符重载
Complex c3 = c2; // 调用拷贝构造函数
Complex c3;
c3 = c2; // 不会调用拷贝构造函数
// 这是因为编译器会默认合成一个赋值运算符重载函数
这里的赋值运算符重载函数必须要定义为成员函数,因为它一定需要用到 this
指针。
Complex &operator=(const Complex &c)
{
if(this != &c) // 因为 this 是一个非 const,而c是const,所以不能写成 *this != c
{
real = c.real;
img = c.img;
}
return *this;
}
自增运算符重载
自增运算符的重载包括两种,一种是前置++
,一种是后置++
。
Complex &operator++()
{ // 前置++
real++;
img++;
return *this;
}
Complex c3;
++c3;
Complex operator++(int i) // 这里的 int i 仅仅用于区别重载
{ // 后置++
real++;
img++;
return *this;
}
Complex c3;
c3++;
前置++版本返回值为引用,其表示进行++
之后的对象;而后置++
表示++
之前的值的对象。这样来看,其实上面后置++
的写法是有问题的,既然后置++
表示++
之前的值的对象,那么应该这样写:
Complex operator++(int i) // 这里的 int i 仅仅用于区别重载
{ // 后置++
Complex tmp = *this;
real++;
img++;
return tmp;
}
Complex c3;
c3++;
输入输出操作符重载
1、输出操作符重载,不能定义为成员函数(因为如果是成员函数,左侧的运算对象必须是本类的对象);
2、可以定义为友元,以便访问私有域;
3、需要 out
内容。
friend void operator<<(ostream &out, const Complex &c);
void operator<<(ostream &out, const Complex &c) // 这里需要输出对象out
{
cout << c.real << "+" << c.img <<endl;
}
采用上述方法时,没有办法连续输出,因为前部分返回类型 void
,不能再继续被使用。为了能够进行连续输出,需要将返回值定义为 ostream
的引用。
ostream & operator<<(ostream &out, const Complex &c)
{
cout << c.real << "+" << c.img; //尽量不要在函数中添加换行符
return out;
}
cout << c1 << c2 << c3;
ostream
是output stream
的简称,即输出流,在C++中用来输出。一个典型的输出流对象就是在C++中标准输出流cout
。在C++中,很少自定义ostream
的对象,更多的是直接使用cout
。ostream
这个类型,往往出现在<<
操作重载中,作为某个类的友元函数出现。
类似的,对于输入操作符的重载,只需要修改以下细节:
iostream & operator>>(istream &in, Complex &c)
{
in >> c.real;
in >> c.img;
return in;
}
cin >> c3;
因为需要修改值,所以不能使用 const
修饰 c
。