11.5 运算符重载
作用:通过函数对运算符进行重新定义,实现对自定义数据类型的操作
注意:只能对自定义数据类型进行操作
11.5.1 算数运算符重载
语法:operator算数符号(),其中算数符号有+ - * / % ++ –
用法:例如使用operator+()对加号进行重载后,Person类的实例化对象可直接使用+相加,有“成员函数”与“全局函数”两种实现方式,也同样可以函数重载
- 成员函数实现加号运算符重载
class Person {
public:
Person(string name, int age) {
m_name = name;
m_age = age;
}
Person operator+(Person& p) {
m_age = m_age + p.m_age;
return *this;
}
string m_name;
int m_age;
};
void test() {
Person p1("Bob", 18);
Person p2("Bob", 19);
Person p3 = p1 + p2;
cout << p3.m_age << endl;
}
- 全局函数实现加号运算符重载
Person operator+(Person& p1, Person& p2) {
p1.m_age = p1.m_age + p2.m_age;
return p1;
}
void test() {
Person p1("Bob", 18);
Person p2("Bob", 19);
Person p3 = p1 + p2;
cout << p3.m_age << endl;
}
operator+()发生函数重载
Person operator+(Person& p1, Person& p2) { // 传入参数为2个Person类的引用
p1.m_age = p1.m_age + p2.m_age;
return p1;
}
Person operator+(Person& p, int AddAge) { // 传入参数为1个Person类的引用与1个int型
p.m_age = p.m_age + AddAge;
return p;
}
void test() {
Person p1("Bob", 18);
Person p2("Bob", 19);
Person p3 = p1 + p2;
Person p4 = p2 + 10;
cout << p3.m_age << endl;
cout << p4.m_age << endl;
}
11.5.2 左移运算符重载
作用:解决无法使用cout << 输出一个自建数据类型
特点:只能在全局函数实现,类内方式会导致cout与p的顺序出错
语法:operator<<()
class Person {
friend ostream& operator<<(ostream& os, Person& p); // 由于函数需要访问私有成员,故做友元声明
public:
Person(string name,int age):m_name(name),m_age(age){}
private:
string m_name;
int m_age;
};
ostream& operator<<(ostream& os, Person& p) { // 左移运算符重载 函数
os << p.m_name << " " << p.m_age; // 做自建数据类型的输出定义
return os;
}
void test() {
Person p("Bob", 18);
cout << p << endl;
}
- 为什么有两个参数,且顺序为
os p?- 左移运算符
<<是二元运算符,若只使用参数p,无法指定数据输出到哪个流 - 因为编译器在调用
cout << p时,会自动把左操作数cout作为operator<<()的第一个参数,右操作数p作为第二个参数,如果顺序颠倒,则传入的参数类型与实际不符,报错
- 左移运算符
- 为什么形参要使用引入的方式传入?
- Person& 的传入方式在之前已经出现过,主要是为了避免不必要的拷贝,提高代码效率,由于该函数并没有对对象的内容进行修改,所以此处的引用传递不是必须的,但是建议这么写
- ostream是标准库中的一个表示输出流的类,由于
std::ostream类是不可拷贝的,其拷贝构造函数是被=delete的,所以当使用值传递时,系统会被删除调用拷贝构造函数引发错误,故必须使用引用传递
- 为什么要返回,且返回的是形参os?
- 需要返回 是类比于
this指针一节的“链式传递”,当不加返回值时,无法做到cout << p << endl, operator<<()结合两个入口参数os和p,可在使用时简化为os << p,当需要进行链式操作时,返回值应该仍可作为<<符号的左值,故返回的是引用值os
- 需要返回 是类比于
11.5.3 递增运算符重载
作用:解决无法使用++自增一个自建数据类型
语法:前置递增 operator++() 后置递增operator++(int)
class Person {
friend ostream& operator<<(ostream& cout, Person& p); // 友元函数声明
public:
Person(string name,int age):m_name(name),m_age(age){} // 构造函数
Person& operator++() { // 前置递运算符重载
++this->m_age;
return *this;
}
Person& operator++(int) { // 后置递增运算符重载
Person temp = *this;
this->m_age++;
return temp;
}
private:
string m_name;
int m_age;
};
ostream& operator<<(ostream& os, Person& p) { // 左移运算符重载
os << p.m_name << p.m_age;
return os;
}
//void test1() { // 前置递增测试
// Person p("Bob", 18);
// cout << ++(++p) << endl;
// cout << p << endl;
//}
void test2() { // 后置递增测试
Person p("Bob", 18);
cout << p++ << endl;
cout << p << endl;
}
前置递增运算符与后置递增运算符重载的区别:
-
前置无需传参,后置需要传单
int,编译器会根据形参情况自动确定前置与后置 -
前置返回当前对象,后置返回临时对象
递减运算符重载同理
11.5.4 赋值运算符重载
作用:解决拥有在堆区开辟属性的类的对象浅拷贝问题
语法:operator=()
知识补充:C++编译器给一个类至少添加4个函数:
-
默认构造函数
-
默认析构函数
-
默认拷贝构造函数
-
赋值运算符重载函数
operator=()
class Person {
friend void test();
public:
Person(int age) { // 构造函数 在堆区开辟空间存储“年龄”的值,并用指针m_age维护
m_age = new int(age);
}
~Person() { // 析构函数 清理在堆区开辟的空间
if (this->m_age != NULL) {
delete this->m_age;
this->m_age = NULL;
}
}
Person& operator=(Person p) {
// this->m_age = p.m_age;
if (this->m_age != NULL) { // 在赋值前先清理在堆区开辟的属性
delete this->m_age;
this->m_age = NULL;
}
this->m_age = new int(*p.m_age); // 深拷贝
return *this; // 可以链式运算
}
private:
string m_name;
int* m_age;
};
void test() {
Person p1(10);
Person p2(20);
Person p3(30);
p3 = p2 = p1; // 从右至左的链式赋值
cout << "p1的年龄为:" << *p1.m_age << endl;
cout << "p2的年龄为:" << *p2.m_age << endl;
cout << "p3的年龄为:" << *p3.m_age << endl;
}
若使用14行的p.m_age = this->m_age,会导致this->m_age与p.m_age指向同一片堆区内存,在析构时令同一个地址被释放两次。
11.5.5 关系运算符重载
作用:解决关系运算符无法对自建数据类型进行判定的问题,关系运算符包括== != >= <= > <
语法:operator==()
class Person {
public:
Person(string name,int age):m_name(name),m_age(age){}
bool operator==(Person p) {
if (this->m_name == p.m_name && this->m_age == p.m_age) {
return true;
}
else
return false;
}
private:
string m_name;
int m_age;
};
void test() {
Person p1("Bob",10);
Person p2("Bob",20);
if (p1 == p2) {
cout << "p1与p2相等" << endl;
}
else {
cout << "p1与p2不相等" << endl;
}
}
11.5.6 函数调用运算符重载
作用:用于重载函数调用运算符(),重载后称为仿函数
语法:operator()()
特点:仿函数的写法不固定,体现在第二个括号中的传参可根据需求任意选择
class MyPrint {
public:
void operator()(string str) {
cout << str << endl;
}
};
void test() {
MyPrint myprint;
myprint("Hello World");
}
匿名对象:类名+()成为匿名对象
匿名函数对象:9-10行的操作可用MyPrint()("Good Morning")来代替,称为匿名函数对象

被折叠的 条评论
为什么被折叠?



