> 文章列表 > C++基础了解-22-C++ 重载运算符和重载函数

C++基础了解-22-C++ 重载运算符和重载函数

C++基础了解-22-C++ 重载运算符和重载函数

@C++ 重载运算符和重载函数

一、C++ 重载运算符和重载函数

C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。

重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。

当调用一个重载函数或重载运算符时,编译器通过把所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。选择最合适的重载函数或重载运算符的过程,称为重载决策

二、C++ 中的函数重载

在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。您不能仅通过返回类型的不同来重载函数。

下面的实例中,同名函数 print() 被用于输出不同的数据类型:

#include <iostream>
using namespace std;class printData
{public:void print(int i) {cout << "整数为: " << i << endl;}void print(double  f) {cout << "浮点数为: " << f << endl;}void print(char c[]) {cout << "字符串为: " << c << endl;}
};int main(void)
{printData pd;// 输出整数pd.print(5);// 输出浮点数pd.print(500.263);// 输出字符串char c[] = "Hello C++";pd.print(c);return 0;
}

整数为: 5
浮点数为: 500.263
字符串为: Hello C++


三、C++ 中的运算符重载

可以重定义或重载大部分 C++ 内置的运算符。这样,就能使用自定义类型的运算符。

重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表

Box operator+(const Box&);

声明加法运算符用于把两个 Box 对象相加,返回最终的 Box 对象。大多数的重载运算符可被定义为普通的非成员函数或者被定义为类成员函数。如果我们定义上面的函数为类的非成员函数,那么我们需要为每次操作传递两个参数,如下所示:

Box operator+(const Box&, const Box&);

下面的实例使用成员函数演示了运算符重载的概念。在这里,对象作为参数进行传递,对象的属性使用 this 运算符进行访问,如下所示:

#include <iostream>
using namespace std;class Box
{public:double getVolume(void){return length * breadth * height;}void setLength( double len ){length = len;}void setBreadth( double bre ){breadth = bre;}void setHeight( double hei ){height = hei;}// 重载 + 运算符,用于把两个 Box 对象相加Box operator+(const Box& b){Box box;box.length = this->length + b.length;box.breadth = this->breadth + b.breadth;box.height = this->height + b.height;return box;}private:double length;      // 长度double breadth;     // 宽度double height;      // 高度
};
// 程序的主函数
int main( )
{Box Box1;                // 声明 Box1,类型为 BoxBox Box2;                // 声明 Box2,类型为 BoxBox Box3;                // 声明 Box3,类型为 Boxdouble volume = 0.0;     // 把体积存储在该变量中// Box1 详述Box1.setLength(6.0); Box1.setBreadth(7.0); Box1.setHeight(5.0);// Box2 详述Box2.setLength(12.0); Box2.setBreadth(13.0); Box2.setHeight(10.0);// Box1 的体积volume = Box1.getVolume();cout << "Volume of Box1 : " << volume <<endl;// Box2 的体积volume = Box2.getVolume();cout << "Volume of Box2 : " << volume <<endl;// 把两个对象相加,得到 Box3Box3 = Box1 + Box2;// Box3 的体积volume = Box3.getVolume();cout << "Volume of Box3 : " << volume <<endl;return 0;
}

Volume of Box1 : 210
Volume of Box2 : 1560
Volume of Box3 : 5400

四、可重载运算符/不可重载运算符

下面是可重载的运算符列表:
C++基础了解-22-C++ 重载运算符和重载函数
下面是不可重载的运算符列表:
C++基础了解-22-C++ 重载运算符和重载函数

五、运算符重载实例

5.1 C++ 一元运算符重载

一元运算符只对一个操作数进行操作,下面是一元运算符的实例:

递增运算符( ++ )和递减运算符( – )
一元减运算符,即负号( - )
逻辑非运算符( ! )
一元运算符通常出现在它们所操作的对象的左边,比如 !obj、-obj 和 ++obj,但有时它们也可以作为后缀,比如 obj++ 或 obj–。

下面的实例演示了如何重载一元减运算符( - )

#include <iostream>
using namespace std;class Distance
{private:int feet;             // 0 到无穷int inches;           // 0 到 12public:// 所需的构造函数Distance(){feet = 0;inches = 0;}Distance(int f, int i){feet = f;inches = i;}// 显示距离的方法void displayDistance(){cout << "F: " << feet << " I:" << inches <<endl;}// 重载负运算符( - )Distance operator- ()  {feet = -feet;inches = -inches;return Distance(feet, inches);}
};
int main()
{Distance D1(11, 10), D2(-5, 11);-D1;                     // 取相反数D1.displayDistance();    // 距离 D1-D2;                     // 取相反数D2.displayDistance();    // 距离 D2return 0;
}

F: -11 I:-10
F: 5 I:-11

5.2 二元运算符重载

二元运算符需要两个参数,下面是二元运算符的实例。我们平常使用的加运算符( + )、减运算符( - )、乘运算符( * )和除运算符( / )都属于二元运算符。就像加(+)运算符。

下面的实例演示了如何重载加运算符( + )。类似地,您也可以尝试重载减运算符( - )和除运算符( / )

#include <iostream>
using namespace std;class Box
{double length;      // 长度double breadth;     // 宽度double height;      // 高度
public:double getVolume(void){return length * breadth * height;}void setLength( double len ){length = len;}void setBreadth( double bre ){breadth = bre;}void setHeight( double hei ){height = hei;}// 重载 + 运算符,用于把两个 Box 对象相加Box operator+(const Box& b){Box box;box.length = this->length + b.length;box.breadth = this->breadth + b.breadth;box.height = this->height + b.height;return box;}
};
// 程序的主函数
int main( )
{Box Box1;                // 声明 Box1,类型为 BoxBox Box2;                // 声明 Box2,类型为 BoxBox Box3;                // 声明 Box3,类型为 Boxdouble volume = 0.0;     // 把体积存储在该变量中// Box1 详述Box1.setLength(6.0); Box1.setBreadth(7.0); Box1.setHeight(5.0);// Box2 详述Box2.setLength(12.0); Box2.setBreadth(13.0); Box2.setHeight(10.0);// Box1 的体积volume = Box1.getVolume();cout << "Volume of Box1 : " << volume <<endl;// Box2 的体积volume = Box2.getVolume();cout << "Volume of Box2 : " << volume <<endl;// 把两个对象相加,得到 Box3Box3 = Box1 + Box2;// Box3 的体积volume = Box3.getVolume();cout << "Volume of Box3 : " << volume <<endl;return 0;
}

Volume of Box1 : 210
Volume of Box2 : 1560
Volume of Box3 : 5400

5.3 关系运算符重载

C++ 语言支持各种关系运算符( < 、 > 、 <= 、 >= 、 == 等等),它们可用于比较 C++ 内置的数据类型。

可以重载任何一个关系运算符,重载后的关系运算符可用于比较类的对象。

下面的实例演示了如何重载 < 运算符,类似地,也可以尝试重载其他的关系运算符

#include <iostream>
using namespace std;class Distance
{private:int feet;             // 0 到无穷int inches;           // 0 到 12public:// 所需的构造函数Distance(){feet = 0;inches = 0;}Distance(int f, int i){feet = f;inches = i;}// 显示距离的方法void displayDistance(){cout << "F: " << feet << " I:" << inches <<endl;}// 重载负运算符( - )Distance operator- ()  {feet = -feet;inches = -inches;return Distance(feet, inches);}// 重载小于运算符( < )bool operator <(const Distance& d){if(feet < d.feet){return true;}if(feet == d.feet && inches < d.inches){return true;}return false;}
};
int main()
{Distance D1(11, 10), D2(5, 11);if( D1 < D2 ){cout << "D1 is less than D2 " << endl;}else{cout << "D2 is less than D1 " << endl;}return 0;
}

D2 is less than D1

5.4 输入/输出运算符重载

C++ 能够使用流提取运算符 >> 和流插入运算符 << 来输入和输出内置的数据类型。您可以重载流提取运算符和流插入运算符来操作对象等用户自定义的数据类型。

在这里,有一点很重要,我们需要把运算符重载函数声明为类的友元函数,这样我们就能不用创建对象而直接调用函数。

下面的实例演示了如何重载提取运算符 >> 和插入运算符 <<

#include <iostream>
using namespace std;class Distance
{private:int feet;             // 0 到无穷int inches;           // 0 到 12public:// 所需的构造函数Distance(){feet = 0;inches = 0;}Distance(int f, int i){feet = f;inches = i;}friend ostream &operator<<( ostream &output, const Distance &D ){ output << "F : " << D.feet << " I : " << D.inches;return output;            }friend istream &operator>>( istream  &input, Distance &D ){ input >> D.feet >> D.inches;return input;            }
};
int main()
{Distance D1(11, 10), D2(5, 11), D3;cout << "Enter the value of object : " << endl;cin >> D3;cout << "First Distance : " << D1 << endl;cout << "Second Distance :" << D2 << endl;cout << "Third Distance :" << D3 << endl;return 0;
}

$./a.out
Enter the value of object :
70
10
First Distance : F : 11 I : 10
Second Distance :F : 5 I : 11
Third Distance :F : 70 I : 10

5.5 ++ 和 – 运算符重载

递增运算符( ++ )和递减运算符( – )是 C++ 语言中两个重要的一元运算符。

下面的实例演示了如何重载递增运算符( ++ ),包括前缀和后缀两种用法。类似地,您也可以尝试重载递减运算符( – )

#include <iostream>
using namespace std;class Time
{private:int hours;             // 0 到 23int minutes;           // 0 到 59public:// 所需的构造函数Time(){hours = 0;minutes = 0;}Time(int h, int m){hours = h;minutes = m;}// 显示时间的方法void displayTime(){cout << "H: " << hours << " M:" << minutes <<endl;}// 重载前缀递增运算符( ++ )Time operator++ ()  {++minutes;          // 对象加 1if(minutes >= 60)  {++hours;minutes -= 60;}return Time(hours, minutes);}// 重载后缀递增运算符( ++ )Time operator++( int )         {// 保存原始值Time T(hours, minutes);// 对象加 1++minutes;                    if(minutes >= 60){++hours;minutes -= 60;}// 返回旧的原始值return T; }
};
int main()
{Time T1(11, 59), T2(10,40);++T1;                    // T1 加 1T1.displayTime();        // 显示 T1++T1;                    // T1 再加 1T1.displayTime();        // 显示 T1T2++;                    // T2 加 1T2.displayTime();        // 显示 T2T2++;                    // T2 再加 1T2.displayTime();        // 显示 T2return 0;
}

H: 12 M:0
H: 12 M:1
H: 10 M:41
H: 10 M:42

注意,int 在 括号内是为了向编译器说明这是一个后缀形式,而不是表示整数。

前缀形式重载调用 Check operator ++ () ,后缀形式重载调用 operator ++ (int)
实例 (++ 重载)

#include <iostream>
using namespace std;class Check
{private:int i;public:Check(): i(0) {  }Check operator ++ (){Check temp;temp.i = ++i;return temp;}// 括号中插入 int 表示后缀Check operator ++ (int){Check temp;temp.i = i++;return temp;}void Display(){ cout << "i = "<< i <<endl; }
};int main()
{Check obj, obj1;    obj.Display(); obj1.Display();// 调用运算符函数,然后将 obj 的值赋给 obj1obj1 = ++obj;obj.Display();obj1.Display();// 将 obj 赋值给 obj1, 然后再调用运算符函数obj1 = obj++;obj.Display();obj1.Display();return 0;
}

i = 0
i = 0
i = 1
i = 1
i = 2
i = 1

实例 (-- 重载)

#include <iostream>
using namespace std;class Check
{private:int i;public:Check(): i(3) {  }Check operator -- (){Check temp;temp.i = --i;return temp;}// 括号中插入 int 表示后缀Check operator -- (int){Check temp;temp.i = i--;return temp;}void Display(){ cout << "i = "<< i <<endl; }
};int main()
{Check obj, obj1;    obj.Display(); obj1.Display();// 调用运算符函数,然后将 obj 的值赋给 obj1obj1 = --obj;obj.Display();obj1.Display();// 将 obj 赋值给 obj1, 然后再调用运算符函数obj1 = obj--;obj.Display();obj1.Display();return 0;
}

i = 3
i = 3
i = 2
i = 2
i = 1
i = 2

5.6 赋值运算符重载

就像其他运算符一样,您可以重载赋值运算符( = ),用于创建一个对象,比如拷贝构造函数。

下面的实例演示了如何重载赋值运算符

#include <iostream>
using namespace std;class Distance
{private:int feet;             // 0 到无穷int inches;           // 0 到 12public:// 所需的构造函数Distance(){feet = 0;inches = 0;}Distance(int f, int i){feet = f;inches = i;}void operator=(const Distance &D ){ feet = D.feet;inches = D.inches;}// 显示距离的方法void displayDistance(){cout << "F: " << feet <<  " I:" <<  inches << endl;}};
int main()
{Distance D1(11, 10), D2(5, 11);cout << "First Distance : "; D1.displayDistance();cout << "Second Distance :"; D2.displayDistance();// 使用赋值运算符D1 = D2;cout << "First Distance :"; D1.displayDistance();return 0;
}

First Distance : F: 11 I:10
Second Distance :F: 5 I:11
First Distance :F: 5 I:11

5.7 下标运算符 [] 重载

下标操作符 [] 通常用于访问数组元素。重载该运算符用于增强操作 C++ 数组的功能。

下面的实例演示了如何重载下标运算符 []

#include <iostream>
using namespace std;
const int SIZE = 10;class safearay
{private:int arr[SIZE];public:safearay() {register int i;for(i = 0; i < SIZE; i++){arr[i] = i;}}int& operator[](int i){if( i >= SIZE ){cout << "索引超过最大值" <<endl; // 返回第一个元素return arr[0];}return arr[i];}
};
int main()
{safearay A;cout << "A[2] 的值为 : " << A[2] <<endl;cout << "A[5] 的值为 : " << A[5]<<endl;cout << "A[12] 的值为 : " << A[12]<<endl;return 0;
}

$ g++ -o test test.cpp
$ ./test
A[2] 的值为 : 2
A[5] 的值为 : 5
A[12] 的值为 : 索引超过最大值
0

5.8 类成员访问运算符 -> 重载

类成员访问运算符( -> )可以被重载,但它较为麻烦。它被定义用于为一个类赋予"指针"行为。运算符 -> 必须是一个成员函数。如果使用了 -> 运算符,返回类型必须是指针或者是类的对象。

运算符 -> 通常与指针引用运算符 * 结合使用,用于实现"智能指针"的功能。这些指针是行为与正常指针相似的对象,唯一不同的是,当您通过指针访问对象时,它们会执行其他的任务。比如,当指针销毁时,或者当指针指向另一个对象时,会自动删除对象。

间接引用运算符 -> 可被定义为一个一元后缀运算符。也就是说,给出一个类:

class Ptr{//...X * operator->();
};

类 Ptr 的对象可用于访问类 X 的成员,使用方式与指针的用法十分相似。例如:

void f(Ptr p )
{p->m = 10 ; // (p.operator->())->m = 10
}

语句 p->m 被解释为 (p.operator->())->m。同样地,下面的实例演示了如何重载类成员访问运算符 ->

#include <iostream>
#include <vector>
using namespace std;// 假设一个实际的类
class Obj {static int i, j;
public:void f() const { cout << i++ << endl; }void g() const { cout << j++ << endl; }
};// 静态成员定义
int Obj::i = 10;
int Obj::j = 12;// 为上面的类实现一个容器
class ObjContainer {vector<Obj*> a;
public:void add(Obj* obj){ a.push_back(obj);  // 调用向量的标准方法}friend class SmartPointer;
};// 实现智能指针,用于访问类 Obj 的成员
class SmartPointer {ObjContainer oc;int index;
public:SmartPointer(ObjContainer& objc){ oc = objc;index = 0;}// 返回值表示列表结束bool operator++() // 前缀版本{ if(index >= oc.a.size() - 1) return false;if(oc.a[++index] == 0) return false;return true;}bool operator++(int) // 后缀版本{ return operator++();}// 重载运算符 ->Obj* operator->() const {if(!oc.a[index]){cout << "Zero value";return (Obj*)0;}return oc.a[index];}
};int main() {const int sz = 10;Obj o[sz];ObjContainer oc;for(int i = 0; i < sz; i++){oc.add(&o[i]);}SmartPointer sp(oc); // 创建一个迭代器do {sp->f(); // 智能指针调用sp->g();} while(sp++);return 0;
}

菜鸟教程,学习记录