对已有的运算符重新进行定义,赋予其新的意义,适应不同的数据类型。
运算符重载分为成员函数实现,全局函数实现。
运算符重载使用的函数名为"operator" + “运算符”,全局函数和成员函数区别在于调用和参数,以下对几个典型的运算符进行重载举例。
- 运算符重载:+、-、*、/;
- 左移运算符:<<;
- 递增(减)运算符:++、–;
- 赋值运算符:=;
- 关系运算符:>、<、==、>=、<=、!=;
- 函数调用运算符:();
使用背景:对于两个自定义的类Card,两个卡片合成时,等级相加后减去和的1/10,不足1按照1来算。
class Card
{
friend void Levelup(); // 嗯哼~
public:
Card(int level, string name) :Level(level), Name(name) // 类的初始化
{
cout << this->Name << "初始化成功!" << endl;
}
Card operator+(Card &c2) { // 成员函数运算符重载
Card temp(0, "new_card");
temp.Level = (int)((this->Level + c2.Level) * 9 / 10);
return temp;
}
private:
int Level;
string Name;
};
void Levelup()
{
Card c1(5, "Card_1"), c2(6, "Card_2");
Card c3 = c1 + c2;
cout << "第一张卡等级为:" << c1.Level << ",名称为:" << c1.Name << endl;
cout << "第二张卡等级为:" << c2.Level << ",名称为:" << c2.Name << endl;
cout << "新卡等级为:" << c3.Level << ",名称为:" << c3.Name << endl;
}
运行截图:
使用背景:对于一个字符串,乘以几就复制几次并输出。
#include#include using namespace std; string operator*(string &str, int num) { string *temp; temp = new string[sizeof(str) * num - (num - 1)]; for (int i = 0; i < num; i++) { *temp += str; } return *temp; } int main() { string str1 = "abc"; string str2 = str1 * 3; // 调用本质为string str2 = operator*(str1, 3); cout << "原本字符串:" << str1 << endl; cout << "复制之后字符串:" << str2 << endl; system("pause"); return 0; }
运行截图:
class MyInt
{
public:
MyInt(int a):myint(a){ }
// 重载前置运算符
MyInt& operator++() // 返回值为引用
{
myint++;
return *this;
}
// 重载后置运算符
MyInt operator++(int) // 返回值为值,并且使用int占位参数
{
// 先记录
MyInt temp = *this;
//后自增
myint++;
// 最后返回记录值
return temp;
} // 这种写法,也就决定了后置递增运算符无法进行链式编程
// 通过两个运算符重载,可以更加清楚的了解到,前置运算符效率更高
private:
int myint;
}
6. 赋值运算符重载
对类初始化时,编译器自动重载赋值操作,用来两个类之间的赋值。但是对于编译器提供的赋值运算符重载是,浅拷贝层次的。为了满足需要,一般会在成员变量有指针的情况下考虑我们自行对赋值运算符进行重载。这里不做仔细讨论。
7. 关系运算符重载值得注意的是:
- 在进行深拷贝时,注意改变的指针是否已经指向堆区的一段空间。如果有,记得先释放,后申请。(养成好习惯!);
- 想要赋值运算符可以实现链式编程,返回值要写为自身的引用;
目的是为了满足用户自定义的类之间的比较运算。
8. 函数调用运算符重载这个运算符重载之后的使用方式非常像函数的调用,因此成为仿函数;
举例:
#include#include using namespace std; class Print { public: void operator()(string str) { cout << str << endl; } }; void print_func(string str) { cout << str << endl; } int main() { Print print_class; print_class("HelloWorld!"); print_func("HelloWorld!"); system("pause"); return 0; }
仿函数非常灵活,没有固定的写法。
9. 运算符重载注意事项10. 放松时刻
- 运算符重载也可以发生函数重载;
- 一般不会利用成员函数重载左移运算符<<,因为无法实现对象p在右侧;在重载左移运算符时,使用
osteam& operator<<(ostream &cout, 类名 p) { // ... return cout; }
- 重载左移运算符配合友元可以实现输出自定义数据类型;
- 重载前置运算符时,返回值类型设置为引用可以进行链式编程;重载后置运算符时,使用占位参数来和前置运算符作以区分,返回值类型应当设置为值;
提一嘴,这点痛苦,终于过去了。
在这儿,基本没有有意思的东西来玩,就很枯燥。不过好在都过去啦!继续加油!



