一、一元运算符重载
一元运算符只对一个操作数进行操作:
- 递增运算符( ++ )和递减运算符(–)
- 一元减运算符,即负号(-)
- 逻辑非运算符(!)
一元运算符通常出现在它们所操作的对象的左边,比如!obj、-obj和++obj,但有时它们也可以作为后缀,比如obj++或obj–。
下面的实例演示了如何重载一元运算符
#include <iostream>
using namespace std;
class Time
{
public:
// 自定义构造函数
Time(int t)
{
second = t;
}
// 获得distance成员数据值
int GetDistance()
{
return second;
}
// 重载前缀递增运算符( ++ ),前置递增就是增加当前对象的值,并且返回当前对象
Time operator ++()
{
return Time(second++);
//distance++;
//return *this; // 也可以使用this指针
}
// 重载前缀递减运算符( -- ) ,减少当前对象的值,并且返回当前对象
Time operator --()
{
return Time(second--);
//distance--;
//return *this; // 也可以使用this指针
}
// 重载后缀递增运算符( ++ ),增加当前对象的值,并且返回增加值之前的该对象
Time operator ++(int)
{
Time origin = *this; // 保存原先未改变的对象
second++;
return origin;
}
// 重载后缀递减运算符( -- ),后置递减就是减少当前对象的值,并且返回减少值之前的该对象
Time operator --(int)
{
Time origin = *this; // 保存原先未改变的对象
second--;
return origin;
}
// 重载一元减运算符,即负号(-)
Time operator -()
{
return Time(-second);
}
private:
int second;
};
int main()
{
Time d1(5);
++d1; // 前缀递增
d1++; // 后缀递增
cout << "重载运算符(++):" << d1.GetDistance() << endl;
--d1; // 前缀递减
--d1; // 后缀递减
cout << "重载运算符(--):" << d1.GetDistance() << endl;
d1 = -d1;
cout << "重载运算符(-):" << d1.GetDistance() << endl;
return 0;
}
/*
输出结果:
重载运算符(++):7
重载运算符(--):5
重载运算符(-):-5
*/
注意:
- 重载递增递减,一定要和指针的递增递减区分开。因为这里的重载操作的是对象,而不是指针(由于指针是内置类型,指针的递增递减是无法重载的),所以一般情况的递增递减是操作对象内部的成员变量。
- 递增和递减分为前置和后置情况,a = ++b;(前置), a = b++;(后置)。因为符号一样,所以给后置版本加一个 int 形参作为区分,这个形参是 0,但是在函数体中是用不到的,只是为了区分前置后置。
二、二元运算符重载
我们平常使用的加运算符(+)、减运算符(-)、乘运算符(*)和除运算符(/)都属于二元运算符。
下面的实例演示了如何重载加运算符(+),减运算符(-)和乘运算符(*)。类似地,您也可以尝试重载除运算符(/)。
#include <iostream>
using namespace std;
class Box
{
public:
Box() { }
Box(double len, double bre, double hei)
{
length = len;
breadth = bre;
height = hei;
}
double GetVolume(void)
{
return length * breadth * height;
}
// 重载 + 运算符,用于把两个 Box 对象相加
Box operator +(const Box &another)
{
Box box;
box.length = this->length + another.length;
box.breadth = this->breadth + another.breadth;
box.height = this->height + another.height;
return box;
}
// 非成员函数的方式重载运算符 -
/* 当 2 个对象相减时是没有顺序要求的,但要重载 - 让其与一个数字相加则有顺序要求,
可以通过加一个友元函数使另一个顺序的输入合法。*/
friend Box operator -(const Box &box1, const double f);
// 重载 * 运算符,用于把两个 Box 对象相乘
Box operator *(const Box &another)
{
Box box;
box.length = this->length * another.length;
box.breadth = this->breadth * another.breadth;
box.height = this->height * another.height;
return box;
}
private:
double length; // 长度
double breadth; // 宽度
double height; // 高度
};
// 非成员函数的方式重载运算符 -
Box operator -(const Box &box1, const double f)
{
Box box;
box.length = box1.length - f;
box.breadth = box1.breadth - f;
box.height = box1.height - f;
return box;
}
int main()
{
Box box1(1.0, 1.0, 1.0);
Box box2(2.0, 2.0, 2.0);
Box box3(0, 0, 0);
Box box4(0, 0, 0);
Box box5(0, 0, 0);
// Box1 的体积
cout << "Volume of box1 : " << box1.GetVolume() << endl;
// Box2 的体积
cout << "Volume of box2 : " << box2.GetVolume() << endl;
// 把两个对象相加,得到 box3
box3 = box1 + box2; // 相当于box3=box1.operator+(box2);
// box3 的体积
cout << "Volume of box3 : " << box3.GetVolume() << endl;
// 把两个对象相减,得到 box3
box4 = box1 - 3;
// box3 的体积
cout << "Volume of box4 : " << box4.GetVolume() << endl;
// 把两个对象相乘,得到 box5
box5 = box1 * box2;
// box5 的体积
cout << "Volume of box5 : " << box5.GetVolume() << endl;
return 0;
}
/*
输出结果:
Volume of box1 : 1
Volume of box2 : 8
Volume of box3 : 27
Volume of box4 : -8
Volume of box5 : 8
*/
三、关系运算符重载
#include <iostream>
using namespace std;
class Distance
{
public:
Distance(int t_len)
{
len = t_len;
}
// 重载 < 运算符
bool operator <(const Distance &another)
{
if (len < another.len)
return true;
else
return false;
}
private:
int len;
};
// 程序的主函数
int main()
{
Distance distant1 = 5;
Distance distant2 = 10;
if (distant1 < distant2)
cout << "distant1 < distant2" << endl;
else
cout << "distant1 >= distant2" << endl;
return 0;
}
/*
输出结果:
distant1 < distant2
*/
四、输入/输出运算符重载
C++ 能够使用流提取运算符>>和流插入运算符<<来输入和输出内置的数据类型。您可以重载流提取运算符和流插入运算符来操作对象等用户自定义的数据类型。
在这里,有一点很重要,我们需要把运算符重载函数声明为类的友元函数,这样我们就能不用创建对象而直接调用函数。
下面的实例演示了如何重载提取运算符>>和插入运算符<<
#include <iostream>
#include <string>
using namespace std;
class Student
{
public:
Student()
{
age = 0;
name = " ";
}
Student(int t_age, string t_name)
{
age = t_age;
name = t_name;
}
friend ostream &operator <<(ostream &out, const Student &stu)
{
out << "age:" << stu.age << " name:" << stu.name << endl;
return out;
}
friend istream &operator >>(istream &in, Student &stu)
{
in >> stu.age >> stu.name;
return in;
}
private:
int age;
string name;
};
// 程序的主函数
int main()
{
Student stu1(18,"xiaoMing");
Student stu2;
cin >> stu2;
cout << "stu1:" << stu1 << endl;
cout << "stu2:" << stu2 << endl;
return 0;
}
/*
输出结果:
20
feng
stu1:age:18 name:xiaoMing
stu2:age:20 name:feng
*/
五、赋值运算符重载
就像其他运算符一样,您可以重载赋值运算符(=),用于创建一个对象,比如拷贝构造函数。
下面的实例演示了如何重载赋值运算符。
#include <iostream>
#include <string>
using namespace std;
class Student
{
public:
Student()
{
age = 0;
name = " ";
}
Student(int t_age, string t_name)
{
age = t_age;
name = t_name;
}
void print()
{
cout << "stu:" << age << " " << name << endl;
}
void operator =(const Student &stu)
{
age = stu.age;
name = stu.name;
}
private:
int age;
string name;
};
// 程序的主函数
int main()
{
Student stu1(18,"xiaoMing");
Student stu2;
stu2 = stu1;
stu2.print();
return 0;
}
/*
输出结果:
stu:18 xiaoMing
*/
六、函数调用运算符 () 重载
函数调用运算符()可以被重载用于类的对象。当重载()时,您不是创造了一种新的调用函数的方式,相反地,这是创建一个可以传递任意数目参数的运算符函数。
下面的实例演示了如何重载函数调用运算符()。
#include <iostream>
using namespace std;
class Distance
{
private:
int feet; // 0 到无穷
int inches; // 0 到 12
public:
// 所需的构造函数
Distance(){
feet = 0;
inches = 0;
}
Distance(int f, int i){
feet = f;
inches = i;
}
// 重载函数调用运算符
Distance operator()(int a, int b, int c)
{
Distance D;
// 进行随机计算
D.feet = a + c + 10;
D.inches = b + c + 100 ;
return D;
}
// 显示距离的方法
void displayDistance()
{
cout << "F: " << feet << " I:" << inches << endl;
}
};
int main()
{
Distance D1(11, 10), D2;
cout << "First Distance : ";
D1.displayDistance();
D2 = D1(10, 10, 10); // invoke operator()
cout << "Second Distance :";
D2.displayDistance();
return 0;
}
七、下标运算符 [] 重载
下标操作符[]通常用于访问数组元素。重载该运算符用于增强操作 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;
}
/*
输出结果:
A[2] 的值为 : 2
A[5] 的值为 : 5
索引超过最大值
A[12] 的值为 : 0
*/
八、类成员访问运算符 -> 重载
类成员访问运算符(->)可以被重载,但它较为麻烦。它被定义用于为一个类赋予 “指针” 行为。运算符->必须是一个成员函数。如果使用了->运算符,返回类型必须是指针或者是类的对象。
运算符->通常与指针引用运算符*结合使用,用于实现"智能指针"的功能。这些指针是行为与正常指针相似的对象,唯一不同的是,当您通过指针访问对象时,它们会执行其他的任务。比如,当指针销毁时,或者当指针指向另一个对象时,会自动删除对象。
间接引用运算符->可被定义为一个一元后缀运算符。也就是说,给出一个类:
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
{
public:
void add(Obj* obj)
{
a.push_back(obj); // 调用向量的标准方法
}
friend class SmartPointer;
private:
vector<Obj*> a;
};
// 实现智能指针,用于访问类 Obj 的成员
class SmartPointer
{
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];
}
private:
ObjContainer oc;
int index;
};
int main()
{
const int sz = 3;
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;
}
/*
输出结果:
10
12
11
13
12
14
*/
注意:
- 运算重载符不可以改变语法结构;
- 运算重载符不可以改变操作数的个数;
- 运算重载符不可以改变优先级;
- 运算重载符不可以改变结合性。