作者简介:专注于C/C++高性能程序设计和开发,理论与代码实践结合,让世界没有难学的技术。包括C/C++、Linux、MySQL、Redis、TCP/IP、协程、网络编程等。
️ CSDN实力新星,社区专家博主
专栏介绍:从零到c++精通的学习之路。内容包括C++基础编程、中级编程、高级编程;掌握各个知识点。
专栏地址:C++从零开始到精通
博客主页:https://blog.csdn.net/Long_xu
上一篇:【030】C++类和对象之友元(friend)详解
运算符重载是C++中一种特殊的语言特性,它允许程序员重新定义现有的运算符,使其适用于自定义类型或类对象。通过运算符重载,可以为自己创建的数据类型定义新的操作行为,增加代码可读性和易用性。
运算符重载的基本概念包括:
语法:定义重载的运算符就像定义函数,只是该函数的名字是operator@,这里的@代表被重载的运算符。例如,可以通过重载"+"运算符来实现两个自定义类型对象相加,并返回一个新对象作为结果。在这种情况下,需要编写一个名为operator+()的重载函数,并在其中定义相应的操作行为。
思路:
(1)弄清楚运算符的运算对象的个数;个数决定了重载函数的参数个数。
(2)识别运算符左边的运算对象是类的对象还是其他:
+ | - | * | / | % | ^ | & | | |
~ | ! | = | < | > | += | -= | *= |
/= | ^= | &= | |= | << | >> | >>= | <<= |
== | != | <= | >= | && | || | ++ | – |
->* | ’ | -> | [] | () | new | delete | new[]和delete[] |
尽量不要重载&&和||,因为无法完成它们的短路特性。
. | :: | .* | ?: | sizeof |
使用全局函数重载运算符必须将全局函数设置为友元。
#include
#include
using namespace std;
class MyPerson {
friend ostream& operator<<(ostream &out, MyPerson &ob);
private:
int num;
string name;
float score;
public:
MyPerson()
{
num = 0;
name = "Lion";
score = 0.0f;
}
MyPerson(int num, string name, float score) :num(num), name(name), score(score)
{
}
};
// 全局函数
ostream& operator<<(ostream &out, MyPerson &ob)
{
out << ob.name << " " << ob.num << " " << ob.score << endl;
return out;
}
int main()
{
MyPerson person;
MyPerson p2(100, "Long", 100.0f);
cout << person << endl;// 相当于operator<<(cout, person);
cout << person << p2 << endl;
return 0;
}
#include
#include
using namespace std;
class MyPerson {
friend ostream& operator<<(ostream &out, MyPerson &ob);
friend istream& operator>>(istream &in, MyPerson &ob);
private:
int num;
string name;
float score;
public:
MyPerson()
{
num = 0;
name = "Lion";
score = 0.0f;
}
MyPerson(int num, string name, float score) :num(num), name(name), score(score)
{
}
};
// 全局函数
ostream& operator<<(ostream &out, MyPerson &ob)
{
out << ob.name << " " << ob.num << " " << ob.score << endl;
return out;
}
istream& operator>>(istream &in, MyPerson &ob)
{
in >> ob.name >> ob.num >> ob.score;
return in;
}
int main()
{
MyPerson person;
cin >> person;
MyPerson p2(100, "Long", 100.0f);
cout << person << endl;// 相当于operator<<(cout, person);
cout << person << p2 << endl;
return 0;
}
#include
#include
using namespace std;
class MyPerson {
friend ostream& operator<<(ostream &out, MyPerson ob);
friend MyPerson operator+(MyPerson &ob1, MyPerson &ob2);
private:
int num;
string name;
float score;
public:
MyPerson()
{
num = 0;
name = "Lion";
score = 0.0f;
}
MyPerson(int num, string name, float score) :num(num), name(name), score(score)
{
}
};
// 全局函数
ostream& operator<<(ostream &out, MyPerson ob)
{
out << ob.name << " " << ob.num << " " << ob.score << endl;
return out;
}
MyPerson operator+(MyPerson &ob1,MyPerson &ob2)
{
MyPerson tmp;
tmp.name = ob1.name + ob2.name;
tmp.num = ob1.num + ob2.num;
tmp.score = ob1.score + ob2.score;
return tmp;
}
int main()
{
MyPerson person(1,"Lion",98.9f);
MyPerson p2(100, "Long", 100.0f);
cout << person + p2 << endl;// 相当于operator<<(cout, person);
return 0;
}
#include
#include
using namespace std;
class MyPerson {
friend ostream& operator<<(ostream &out, MyPerson ob);
private:
int num;
string name;
float score;
public:
MyPerson()
{
num = 0;
name = "Lion";
score = 0.0f;
}
MyPerson(int num, string name, float score) :num(num), name(name), score(score)
{
}
// 成员函数实现 重载 + 运算符
MyPerson operator+(MyPerson &ob2)
{
MyPerson tmp;
tmp.name = name + ob2.name;
tmp.num = num + ob2.num;
tmp.score = score + ob2.score;
return tmp;
}
};
// 全局函数
ostream& operator<<(ostream &out, MyPerson ob)
{
out << ob.name << " " << ob.num << " " << ob.score << endl;
return out;
}
/*
MyPerson operator+(MyPerson &ob1,MyPerson &ob2)
{
MyPerson tmp;
tmp.name = ob1.name + ob2.name;
tmp.num = ob1.num + ob2.num;
tmp.score = ob1.score + ob2.score;
return tmp;
}
*/
int main()
{
MyPerson person(1,"Lion",98.9f);
MyPerson p2(100, "Long", 100.0f);
cout << person + p2 << endl;// 相当于person.operator+(p2);
return 0;
}
#include
#include
using namespace std;
class MyPerson {
friend ostream& operator<<(ostream &out, MyPerson ob);
private:
int num;
string name;
float score;
public:
MyPerson()
{
num = 0;
name = "Lion";
score = 0.0f;
}
MyPerson(int num, string name, float score) :num(num), name(name), score(score)
{
}
// 成员函数实现重载 + 运算符
MyPerson operator+(MyPerson &ob2)
{
MyPerson tmp;
tmp.name = name + ob2.name;
tmp.num = num + ob2.num;
tmp.score = score + ob2.score;
return tmp;
}
// 成员函数实现 重载 == 运算符
bool operator==(MyPerson &ob2)
{
if (name == ob2.name && num == ob2.num && score == ob2.score)
return true;
return false;
}
};
// 全局函数
ostream& operator<<(ostream &out, MyPerson ob)
{
out << ob.name << " " << ob.num << " " << ob.score << endl;
return out;
}
/*
MyPerson operator+(MyPerson &ob1,MyPerson &ob2)
{
MyPerson tmp;
tmp.name = ob1.name + ob2.name;
tmp.num = ob1.num + ob2.num;
tmp.score = ob1.score + ob2.score;
return tmp;
}
*/
int main()
{
MyPerson person(1,"Lion",98.9f);
MyPerson p2(100, "Long", 100.0f);
if (person == p2)
{
cout << "相等" << endl;
}
else
cout << "不相等" << endl;
MyPerson p3(1, "Lion", 98.9f);
if (person == p3)
{
cout << "相等" << endl;
}
else
cout << "不相等" << endl;
return 0;
}
重载的 ++ 和 – 运算符会复杂一些,因为希望能根据它们出现在所作用对象的前面还是后面来调用不同的函数。解决办法很简单:利用函数重载的占位符机制。例如,当编译器看到++a(前置++)时调用operator++(a);当编译器看到a++(后置++)时调用operator++(a,int)。
类名称 operator++(int)
{
// 先保存旧的值
// 自增
// return 返回旧的值
}
代码示例:
#include
#include
using namespace std;
class MyPerson {
friend ostream& operator<<(ostream &out, MyPerson ob);
private:
int num;
string name;
float score;
public:
MyPerson()
{
num = 0;
name = "Lion";
score = 0.0f;
}
MyPerson(int num, string name, float score) :num(num), name(name), score(score)
{
}
// 成员函数实现重载 + 运算符
MyPerson operator+(MyPerson &ob2)
{
MyPerson tmp;
tmp.name = name + ob2.name;
tmp.num = num + ob2.num;
tmp.score = score + ob2.score;
return tmp;
}
// 成员函数实现 重载 == 运算符
bool operator==(MyPerson &ob2)
{
if (name == ob2.name && num == ob2.num && score == ob2.score)
return true;
return false;
}
// 成员函数实现 重载 后置++ 运算符
MyPerson operator++(int)
{
// 保存旧值
MyPerson old = *this;
// 自增
this->name = this->name + this->name;
this->num++;
this->score++;
// 返回旧值
return old;
}
};
// 全局函数
ostream& operator<<(ostream &out, MyPerson ob)
{
out << ob.name << " " << ob.num << " " << ob.score << endl;
return out;
}
/*
MyPerson operator+(MyPerson &ob1,MyPerson &ob2)
{
MyPerson tmp;
tmp.name = ob1.name + ob2.name;
tmp.num = ob1.num + ob2.num;
tmp.score = ob1.score + ob2.score;
return tmp;
}
*/
int main()
{
MyPerson person(1,"Lion",98.9f);
MyPerson p2;
p2 = person++;
cout << p2 << endl;
cout << person << endl;
return 0;
}
类名称 operator++(int)
{
// 自增
// return 返回当前新的值
}
示例:
#include
#include
using namespace std;
class MyPerson {
friend ostream& operator<<(ostream &out, MyPerson ob);
private:
int num;
string name;
float score;
public:
MyPerson()
{
num = 0;
name = "Lion";
score = 0.0f;
}
MyPerson(int num, string name, float score) :num(num), name(name), score(score)
{
}
// 成员函数实现重载 + 运算符
MyPerson operator+(MyPerson &ob2)
{
MyPerson tmp;
tmp.name = name + ob2.name;
tmp.num = num + ob2.num;
tmp.score = score + ob2.score;
return tmp;
}
// 成员函数实现 重载 == 运算符
bool operator==(MyPerson &ob2)
{
if (name == ob2.name && num == ob2.num && score == ob2.score)
return true;
return false;
}
// 成员函数实现 重载 后置++ 运算符
MyPerson operator++(int)
{
// 保存旧值
MyPerson old = *this;
// 自增
this->name = this->name + this->name;
this->num++;
this->score++;
// 返回旧值
return old;
}
// 成员函数实现 重载 前置++ 运算符
MyPerson operator++()
{
// 自增
this->name = this->name + this->name;
this->num++;
this->score++;
// 返回新值
return *this;
}
};
// 全局函数
ostream& operator<<(ostream &out, MyPerson ob)
{
out << ob.name << " " << ob.num << " " << ob.score << endl;
return out;
}
/*
MyPerson operator+(MyPerson &ob1,MyPerson &ob2)
{
MyPerson tmp;
tmp.name = ob1.name + ob2.name;
tmp.num = ob1.num + ob2.num;
tmp.score = ob1.score + ob2.score;
return tmp;
}
*/
int main()
{
MyPerson person(1,"Lion",98.9f);
MyPerson p2;
p2 = ++person;
cout << p2 << endl;
cout << person << endl;
return 0;
}
输出:
LionLion 2 99.9
LionLion 2 99.9
重载–运算符的代码和 ++的类似,直接参考上述的重载 ++运算符代码。
此案例会重载以下的运算符:[]、<<、>>、+、=、>、<、==。
#include
#include
using namespace std;
class MyString {
//全局函数重载 << 运算符
friend ostream& operator<<(ostream &out, MyString str);
//全局函数重载 >> 运算符
friend istream& operator>>(istream &in, MyString &ob);
private:
char *str;//保存字符串
int size;
public:
MyString();
MyString(const char *str);
MyString(const MyString &ob);
~MyString();
int getSize();
// 成员函数重载 [] 运算符
char& operator[](int pos);
// 成员函数重载 + 运算符
MyString operator+(MyString &ob);
MyString operator+(const char *str);
// 成员函数重载 = 运算符
MyString& operator=(MyString &ob);
MyString& operator=(const char *str);
// 成员函数重载 > 运算符
bool operator>(MyString &ob);
bool operator>(const char *str);
// 成员函数重载 < 运算符
bool operator<(MyString &ob);
bool operator<(const char *str);
// 成员函数重载 == 运算符
bool operator==(MyString &ob);
bool operator==(const char *str);
};
MyString::MyString()
{
str = NULL;
size = 0;
}
MyString::MyString(const char *str)
{
this->size = strlen(str);
this->str = new char[this->size + 1];
strcpy(this->str, str);
}
MyString::MyString(const MyString &ob)
{
size = ob.size;
this->str = new char[size + 1];
memset(this->str, 0, size + 1);
strncpy(this->str, ob.str, size);
}
MyString::~MyString()
{
if (str != NULL)
{
delete[] str;
str = NULL;
}
}
int MyString::getSize()
{
return size;
}
// 成员函数重载 [] 运算符
char& MyString::operator[](int pos)
{
if (pos < 0 || pos >= size)
{
cout << "访问越界" << endl;
exit(-1);
}
return str[pos];
}
//全局函数重载 << 运算符
ostream& operator<<(ostream &out, MyString str)
{
out << str.str;
return out;
}
//全局函数重载 >> 运算符
istream& operator>>(istream &in, MyString &ob)
{
char buf[128] = "";
cin >> buf;
if (ob.str != NULL)
{
delete[] ob.str;
ob.str = NULL;
}
ob.size = strlen(buf);
ob.str = new char[ob.size + 1];
memset(ob.str, 0, ob.size + 1);
strcpy(ob.str, buf);
return in;
}
// 成员函数重载 + 运算符
MyString MyString::operator+(MyString &ob)
{
MyString tmp;
tmp.size = this->size + ob.size;
tmp.str = new char[tmp.size + 2];
memset(tmp.str, 0, tmp.size + 2);
strcpy(tmp.str, this->str);
strcat(tmp.str, ob.str);
return tmp;
}
MyString MyString::operator+(const char *str)
{
MyString tmp;
tmp.size = this->size + strlen(str);
tmp.str = new char[tmp.size + 1];
memset(tmp.str, 0, tmp.size + 1);
strcpy(tmp.str, this->str);
strcat(tmp.str, str);
return tmp;
}
// 成员函数重载 = 运算符
MyString& MyString::operator=(MyString &ob)
{
if (this->str != NULL)
{
delete[] this->str;
this->str = NULL;
}
this->size = ob.size;
this->str = new char[this->size + 1];
memset(this->str, 0, this->size + 1);
strcpy(this->str, ob.str);
return *this;
}
MyString& MyString::operator=(const char *str)
{
if (this->str != NULL)
{
delete[] this->str;
this->str = NULL;
}
this->size = strlen(str);
this->str = new char[this->size + 1];
memset(this->str, 0, this->size + 1);
strcpy(this->str, str);
return *this;
}
// 成员函数重载 > 运算符
bool MyString::operator>(MyString &ob)
{
if (this->str == NULL || ob.str == NULL)
exit(-1);
if (strcmp(this->str, ob.str) > 0)
return true;
return false;
}
bool MyString::operator>(const char *str)
{
if (this->str == NULL || str == NULL)
exit(-1);
if (strcmp(this->str, str) > 0)
return true;
return false;
}
// 成员函数重载 < 运算符
bool MyString::operator<(MyString &ob)
{
if (this->str == NULL || ob.str == NULL)
exit(-1);
if (strcmp(this->str, ob.str) < 0)
return true;
return false;
}
bool MyString::operator<(const char *str)
{
if (this->str == NULL || str == NULL)
exit(-1);
if (strcmp(this->str, str) < 0)
return true;
return false;
}
// 成员函数重载 == 运算符
bool MyString::operator==(MyString &ob)
{
if (this->str == NULL || ob.str == NULL)
exit(-1);
if (strcmp(this->str, ob.str) == 0)
return true;
return false;
}
bool MyString::operator==(const char *str)
{
if (this->str == NULL || str == NULL)
exit(-1);
if (strcmp(this->str, str) == 0)
return true;
return false;
}
int main()
{
MyString str = "Hello World!";
cout << str[6] << endl;
str[6] = 'Y';
cout << str[6] << endl;
cout << str << endl;
MyString str2;
cin >> str2;
cout << str2;
MyString str3 = "hello";
MyString str4 = "world";
cout << str3 + str4 << endl;
cout << str3 + "Lion" << endl;
MyString str5 = "str5";
MyString str6 = "str6";
cout << str6 << endl;
str6 = str5;
cout << str6 << endl;
str6 = "hi,str6";
cout << str6 << endl;
if (str5 > str6)
cout << "str5 > str6" << endl;
else
cout << "str5 <= str6" << endl;
return 0;
}
重载 () 运算符一般用于为算法提供策略。当对象或匿名对象和 () 结合时 会触发重载函数调用运算符。
这种重载() 的对象,也称为仿函数。
示例:
#include
using namespace std;
class Print {
public:
void operator() (const char *str){
cout << str << endl;
}
};
int main()
{
Print obj;
obj("hi,仿函数");
Print()("匿名对象调用");
return 0;
}
输出:
hi,仿函数
匿名对象调用
智能指针主要解决堆区空间的对象释放问题。
示例:
#include
using namespace std;
class Data {
public:
Data()
{
cout << "Data无参构造" << endl;
}
~Data()
{
cout << "Data析构函数" << endl;
}
void func()
{
cout << "Data func" << endl;
}
};
// 智能指针类,为Data服务
class SmartPointer {
private:
Data *p;
public:
SmartPointer(Data *p)
{
this->p = p;
}
~SmartPointer()
{
delete p;
}
// 重载->运算符
Data* operator->()
{
return p;
}
Data& operator*()
{
return *p;
}
};
int main()
{
SmartPointer sp(new Data);
//sp.operator->()->func();
sp->func();
(*sp).func();
return 0;
}
输出:
Data无参构造
Data func
Data func
Data析构函数
建议不去重载operator 和 operator || 的原因是 无法在这两种情况下实现内置操作符的完整语义。内置版本特殊之处在于:内置版本的 && 和 || 会首先计算左边的表达式,如果这完全能够决定结果,就不需要计算右边的表达式了,而且能够保证不需要。而函数调用总是在函数执行前对所有参数进行求值。
示例:
class Complex {
public:
int flag;
public:
Complex(int flag)
{
this->flag = flag;
}
// 重载 +=运算符
Complex& operator+=(Complex& cmplx)
{
this->flag = this->flag + cmplx.flag;
return *this;
}
// 重载 && 运算符
bool operator&&(Complex& cmplx)
{
return this->flag && cmplx.flag;
}
};
int main()
{
Complex com0(0);// flag=0
Complex com1(1);// flag=1
/*
* 原来的情况:应该从左边往右边运算,左边为假则退出运算,结果为假
* 现在却是:先运算(com0 += com1),导致com0的flag结果为(com0 += com1)的值
* com0.flag=1,从而输出了 true。
*/
if (com0 && (com0 += com1))
{
cout << "true" << endl;
}
else
{
cout << "false" << endl;
}
return 0;
}
C++重载运算符是一种允许程序员自定义运算符行为的机制。通过重载运算符,我们可以定义自己的类类型,并使其支持像加、减、乘等运算符,以及比较运算符等。
在 C++ 中,有些运算符可以被重载(如 +, -, *, / 等),而有些则不能被重载(如 ., ?: 等)。对于可以被重载的运算符,我们只需要按照一定的规则来实现相应的函数即可。
重载函数必须是一个成员函数或者友元函数。如果是成员函数,则第一个参数必须是当前对象的引用或指针;如果是友元函数,则没有这个限制。
不同的运算符要求不同的参数个数和类型。例如,二元操作符通常需要两个参数,一元操作符只需要一个参数。
运算符不能改变其操作数的值。也就是说,在执行完某个操作之后,原来的操作数必须保持不变。
除了赋值运算符外,其他所有重载操作都应该返回新对象或对象引用。
如果你想使用默认参数,则应该将它们放在最后一个形参列表中,并在声明和定义中都指定它们。
可以使用 const 关键字来表示函数不会改变对象的状态。这在一些情况下非常有用,例如定义比较运算符时。
重载运算符必须满足所有运算符本身的语义和优先级规则,否则可能会导致意外的结果。