运算符重载和函数重载
1. 定义
重载就是赋予新的含义。函数重载可以让一个函数名有多种功能,在不同情况下有不同的操作,运算符重载也是同样。
实际上,我们已经在不知不觉中使用了运算符重载,例如:+号可以对不同类型的数据进行加法操作; << 既是位移运算符,又可以向控制台输出数据,C++本身对这些运算符进行了重载。
C++ 也允许程序员自己重载运算符,这给我们带来了很大的便利。
2. 作用
用复数类举例
//Complex c3 = c1 + c2;
//原因 Complex是用户自定义类型,编译器根本不知道如何进行加减,编译器给提供了一种机制,让用户自己去完成,自定义类型的加减操作。
//这个机制就是运算符重载机制
3. 规则
1)不是所有运算符都可以重载
能重载的运算符:
+ - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> <<= >>= == != <= >= && || ++ -- , ->* -> () [] new new[] delete delete[]
[]是下标运算符,()是函数调用运算符。
不能重载的运算符:
长度运算符sizeof、条件运算符: ?、成员选择符.和域解析运算符::以及 ->成员指针访问运算符、#预处理符号。
2)重载不能改变运算符的优先级和结合性。
3)重载不会改变运算符的用法。
4)运算符重载函数不能有默认的参数,否则就改变了运算符操作数的个数,这显然是错误的。
5)运算符重载函数既可以作为类的成员函数,也可以作为全局函数。
将运算符重载函数作为类的成员函数时,二元运算符的参数只有一个,一元运算符不需要参数。之所以少一个参数,是因为这个参数是隐含的。
另外,将运算符重载函数作为全局函数时,一般都需要在类中将该函数声明为友元函数。因为,该函数大部分情况下都需要使用类的 private 成员。
6)箭头运算符->、下标运算符[ ]、函数调用运算符( )、赋值运算符=只能以成员函数的形式重载。
4. 示例
4.1 函数重载
在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同,不能仅通过返回类型的不同来重载函数。
下面的实例中,同名函数 add() 被用于求和:
#include <iostream>
using namespace std;
class printData
{
public:
void add(int i, int j) {
int num = i + j;
cout << "两个整数和为: " << num << endl;
}
void add(float f, float g) {
float num = f + g;
cout << "两个浮点数和为: " << num << endl;
}
void add(int f, int g, double k) {
double num = f + g + k;
cout << "三个数和: " << num << endl;
}
};
int main(void)
{
printData pd;
pd.add(5, 5);
pd.add(5.5f, 4.5f);//传入的参数必须加f
// 如果传入的参数不带f,会报错
// 原因是传入的参数5.5,C++里直接的实数字面值常量系统会解释为double类型,那么从double可以隐式转化为float或是int,编译器就会报错,有两个函数可以调用,到底用哪个?修改为pd.add(5.5f, 4.5f),就好了,这样显式声明为float类型。
pd.add(5, 5, 1.2);
return 0;
}
4.2 运算符重载
您可以重定义或重载大部分 C++ 内置的运算符。这样,您就能使用自定义类型的运算符。
重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。
Box operator+(const Box&);
声明加法运算符用于把两个 Box 对象相加,返回最终的 Box 对象。大多数的重载运算符可被定义为普通的非成员函数或者被定义为类成员函数。如果我们定义上面的函数为类的非成员函数,那么我们需要为每次操作传递两个参数,如下所示:
Box operator+(const Box&, const Box&);
下面的实例使用成员函数演示了运算符重载的概念。在这里,对象作为参数进行传递,对象的属性使用 this 运算符进行访问,如下所示:
#include <iostream>
using namespace std;
class Fruit
{
public: //如果不写,默认是private (struct 默认是 public, class 默认是 private)
Fruit() { cout << "Fruit constructs..." << endl; }
virtual ~Fruit() { cout << "Fruit deconstructs..." << endl; }
public:
Fruit operator + (const Fruit & fruit)
{
cout << "operator + " << endl;
Fruit f;
f.m_iCount = this->m_iCount + fruit.m_iCount;
return f;
}
int getFruitCount()
{
return m_iCount;
}
void setFruitCount(int count)
{
m_iCount = count;
}
private:
int m_iCount;
};
class Apple : public Fruit
{
public:
Apple()
{
cout << "Apple constructs..." << endl;
}
~Apple() { cout << "Apple deconstructs..." << endl; }
private:
int m_iCount;
};
class Orange : public Fruit
{
public:
Orange()
{
cout << "Orange constructs..." << endl;
}
~Orange() { cout << "Orange deconstructs..." << endl; }
private:
int m_iCount;
};
int main()
{
Apple a;
Orange o;
Fruit f;
a.setFruitCount(5);
o.setFruitCount(10);
f = a + o;
cout << "Fruit count is " << f.getFruitCount() << endl;
return 0;
}