05 流运算符和一元运算符的重载

1. 流插入运算符和流提取运算符的重载

  • cout 是在 iostream 中定义的,ostream 类的对象。

  • “<<” 能用在cout 上是因为,在iostream 里对 “<<” 进行了重载。

例题:假定c是Complex复数类的对象,现在希望写“cout << c;”,就能以“a+bi”的形式输出c的值,写“cin>>c;”,就能从键盘接受“a+bi”形式的输入,并且使得c.real = a,c.imag = b。

解答:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
class Complex
{
double real, imag;

public:
Complex(double r = 0, double i = 0) : real(r), imag(i){};
friend ostream &operator<<(ostream &cout,const Complex &c);
friend istream &operator>>(istream &cin, Complex &c);
};
ostream &operator<<(ostream &cout, const Complex &c)
{
cout << c.real << "+" << c.imag << "i"; //以"a+bi"的形式输出
return cout;
}
istream &operator>>(istream &cin, Complex &c)
{
string s;
cin >> s; //将"a+bi"作为字符串读入, “a+bi” 中间不能有空格
int pos = s.find("+", 0);
//printf("%s\n",s.c_str());
string sTmp = s.substr(0, pos); //分离出代表实部的字符串
c.real = stof(sTmp); // atof库函数能将const char*指针指向的内容转换成 float
sTmp = s.substr(pos + 1, s.length() - 2); //分离出代表虚部的字符串
c.imag = stof(sTmp);
return cin;
}

int main()
{
Complex c,n;
cin >> c >> n;
cout << c << "," << n;
return 0;
}

输入:

1
2
2+3i
4+5i

输出结果:

1
2+3i,4+5i

2. 自增、自减运算符的重载和类型转换运算符

  • 自增运算符++、自减运算符–有前置/后置之分,为了区分所重载的是前置运算符还是后置运算符,C++规定:

    • 前置运算符作为一元运算符重载

      重载为成员函数:

      T & operator++();

      T & operator--();

      重载为全局函数:

      T1 & operator++(T2);

      T1 & operator—(T2);

    • 后置运算符作为二元运算符重载,多写一个没用的参数:

      重载为成员函数:

      T operator++(int);

      T operator--(int);

      重载为全局函数:

      T1 operator++(T2,int );

      T1 operator—( T2,int);

但是在没有后置运算符重载而有前置重载的情况下,在vs中,obj++ 也调用前置重载,而dev则令 obj ++ 编译出错

  • 类型转换运算符:

operator int ( ) { return n; }

这里,int 作为一个类型强制转换运算符被重载, 此后

1
2
Demo s;
(int) s ;//等效于 s.int();

注意:类型强制转换运算符被重载时不能写返回值类型,实际上其返回值类型就是该类型强制转换运算符代表的类型

实际案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include<iostream>
using namespace std;

class CDemo
{
private:
int n;

public:
CDemo(int i = 0) : n(i) {}
CDemo &operator++(); //用于前置形式
CDemo operator++(int); //用于后置形式
operator int() { return n; }
friend CDemo &operator--(CDemo &);
friend CDemo operator--(CDemo &, int);
};
CDemo &CDemo::operator++()
{ //前置 ++
n++;
return *this;
} // ++s即为: s.operator++();
CDemo CDemo::operator++(int k)
{ //后置 ++
CDemo tmp(*this); //记录修改前的对象
n++;
return tmp; //返回修改前的对象
} // s++即为: s.operator++(0);
CDemo &operator--(CDemo &d)
{ //前置--
d.n--;
return d;
} //--s即为: operator--(s);
CDemo operator--(CDemo &d, int)
{ //后置--
CDemo tmp(d);
d.n--;
return tmp;
} // s--即为: operator--(s, 0);
int main()
{
CDemo d(5);
//因为写了类型转换运算符,所以以下所有输出检测到输出对象的时候能瞬间把对象转换成int,
//于是就按照int类型输出
cout << (d++) << ","; //等价于 d.operator++(0);
cout << d << ",";
cout << (++d) << ","; //等价于 d.operator++();
cout << d << endl;
cout << (d--) << ","; //等价于 operator--(d,0);
cout << d << ",";
cout << (--d) << ","; //等价于 operator--(d);
cout << d << endl;
return 0;
}
  • 运算符重载的注意事项
  1. C++不允许定义新的运算符 ;

  2. 重载后运算符的含义应该符合日常习惯;

  3. 运算符重载不改变运算符的优先级

  4. 以下运算符不能被重载:“.”、“.*”、“::”、“?:”、sizeof;

  5. 重载运算符()、[]、->或者赋值运算符=时,运算符重载函数必须声明为类的成员函数。