前言:C++语言给使用提供重载机制,大大提高的使用的灵活性。
1 函数重载概念
函数重载概念
函数重载(Function Overload)
- 用同一个函数名定义不同的函数
- 当函数名和不同的参数搭配时函数的含义不同
函数重载的判断标准
- 函数中参数个数不同
- 函数中参数类型不同
- 函数中参数顺序不同
注意:
不能把返回值作为函数重载的条件,原因是编译器在编译时不会去判断函数的返回类型,函数只有调用后,编译器才会去验证返回类型,所以返回值不能作为函数重载的依据。
常函数 const 可以作为函数重载判断依据,原因:重载[]运算符时,有没有const的区别是:有const只读,没有const读写都可以。
所谓重载,就是重新赋予新的含义。函数重载就是对一个已有的函数赋予新的含义,使之实现新功能,因此,一个函数名就可以用来代表不同功能的函数,也就是”一名多用”。
运算符也可以重载。实际上,我们已经在不知不觉之中使用了运算符重载。例如,大 家都已习惯于用加法运算符”+”对整数、单精度数和双精度数进行加法运算,如5+8, 5.8 +3.67等,其实计算机对整数、单精度数和双精度数的加法操作过程是很不相同的, 但由于C++已经对运算符”+”进行了重载,所以就能适用于int, float, doUble类型的运算。
又如”<<“是C++的位运算中的位移运算符(左移),但在输出操作中又是与流对 象cout 配合使用的流插入运算符,”>>“也是位移运算符(右移),但在输入操作中又是与流对象 cin 配合使用的流提取运算符。这就是运算符重载(operator overloading)。C++系统对”<<“和”>>“进行了重载,用户在不同的场合下使用它们时,作用是不同 的。对”<<“和”>>“的重载处理是放在头文件stream中的。因此,如果要在程序中用”<< “和”>>”作流插入运算符和流提取运算符,必须在本文件模块中包含头文件stream(当然还应当包括”using namespace std“)。
现在要讨论的问题是:用户能否根据自己的需要对C++已提供的运算符进行重载,赋予它们新的含义,使之一名多用。?
2 运算符重载入门技术推演
为什么会用运算符重载机制,这样可以大大提高代码的可读性可灵活性!
我们举一个例子:
复数类举例
Complex c3 = c1 + c2; 这个语句这个编译器无法编译通过。因为编译器是无法知道这个+是执行什么,但是编译器给提供了一种机制,让用户自己去完成,自定义类型的加减操作,符号运算,这个机制就是运算符重载机制。
运算符重载的本质是一个函数
#include <iostream>
using namespace std;
class Complex
{
public:
int real; //复数实部
int imaginary; //复数虚部
public:
Complex(int real = 0, int imaginary = 0)
{
this->real = real;
this->imaginary = imaginary;
}
public:
void printComplex()
{
cout << real << " + " << imaginary << "i " << endl;
}
};
Complex operator+(Complex& c1, Complex& c2)
{
Complex tmp(c1.real + c2.real, c1.imaginary + c2.imaginary);
return tmp;
}
void main()
{
Complex c1(1, 2), c2(3, 4);
Complex c3 = c1 + c2; //思考C++编译器如何支持操作符重载机制的 (根据类型)
c3.printComplex();
system("pause");
return;
}
输出结果:
这个就是通过我们设置一个全局函数满足了自定义复数+运算。所以运算符重载的本质是一个函数 另外也可以通过成员函数和友元函数的形式实现符号重载。
全局函数建议使用友元函数在类中定义保证类的封装低耦合。
这样存在一个细节问题:是不是所有的符号都可以进行符号重载,答案是否定的。
运算符重载的两种方法
- 运算符函数可以重载为成员变量或者友元函数
- 关键不同在于成员函数隐含着this指针,友元函数不含有this指针
- 不管是成员函数还是友元函数的符号重载,运算符的方法相同。但是传递参数的方法不同,实现的代码的方式也不同。
上面的复数加法的实现也可以如下:
#include <iostream>
using namespace std;
class Complex
{
private:
int real; //复数实部
int imaginary; //复数虚部
public:
Complex(int real = 0, int imaginary = 0)
{
this->real = real;
this->imaginary = imaginary;
}
public:
void printComplex()
{
cout << real << " + " << imaginary << "i " << endl;
}
Complex operator+(Complex& c2)
{
Complex tmp(this->real + c2.real, this->imaginary + c2.imaginary);
return tmp;
}
};
//Complex operator+(Complex& c1, Complex& c2)
//{
// Complex tmp(c1.real + c2.real, c1.imaginary + c2.imaginary);
// return tmp;
//}
void main()
{
Complex c1(1, 2), c2(3, 4);
Complex c3 = c1 + c2; //思考C++编译器如何支持操作符重载机制的 (根据类型)
c3.printComplex();
system("pause");
return;
}
前置和后置运算符总结
C++中通过一个占位参数来区分前置运算和后置运算
定义运算符重载函数名的步骤
全局函数、类成员函数方法实现运算符重载步骤
- 要承认操作符重载是一个函数,写出函数名称operator+ ()
- 根据操作数,写出函数参数
- 根据业务,完善函数返回值(看函数是返回引用 还是指针 元素),及实现函数业务
友元函数和成员函数选择方法
- 当无法修改左操作数的类时,使用全局函数进行重载
- =, [], ()和->操作符只能通过成员函数进行重载
用友元函数 重载 << >>操作符
- istream 和 ostream 是 C++ 的预定义流类
- cin 是 istream 的对象,cout 是 ostream 的对象
- 运算符 << 由ostream 重载为插入操作,用于输出基本类型数据
- 运算符 >> 由 istream 重载为提取操作,用于输入基本类型数据
- 用友员函数重载 << 和 >> ,输出和输入用户自定义的数据类型
3)友元函数重载操作符使用注意点
友员函数重载运算符常用于运算符的左右操作数类型不同的情况