C++ 面向对象-运算符的重载
本文最后更新于:2022年4月22日 上午
面向对象-运算符的重载
加号(+)运算符的重载
在 C++
程序中,两个数字进行相加,编译器是能够正确的计算结果的,但是如果是两个对象进行相加,编译器将不知道该如何处理这个情况,这个时候,我们给了重载这个对象的 加号运算符,让编译器明确当这两个对象进行相加的时候该如何处理
class User {
public:
int age;
User(int age) {
this->age = age;
}
// 重写 + 运算符
User& operator+(User& p) {
User newp(this->age + p.age);
return newp;
}
};
void two_test1() {
User p1(10);
User p2(20);
// 重写 加号运算符之后,编译器就知道两个 User 对象进行相加的时候需要如何操作
User p3 = p1 + p2;
// 默认是报错的
cout << p3.age << endl;
}
输出
30
左移(<<)运算符的重载
之前我们使用 cout << xxx;
只能打印一些基本值如 string
,int
等,如果我们一个 class
中有很多成员属性
我们希望能够将这些成员属性都打印出来(类似于 java
中的重写 toString
方法),我们就可以重写 左移运算符
因为我们一直是使用 cout
进行打印的,cout
是在 输出流(ostream
) 中的,所以我们这里接受的第一个参数是 ostream& cout
void operator<<(ostream& cout, User& u) {
cout << "user age:" << u.age << endl;
};
测试 (不能连续传入的参数,如: cout << u << endl;
会报错 )
cout << u ;
输出
user age:10
优化:void operator<<(ostream &out, User &u)
的方式是无返回值的方式,意味着 cout << u << xxx;
在接收到 第一个合法参数后就不允许再次接收了其它的参数了 ,如果要进行优化的话,我们可以返回一个 cout
,这样就就能继续接收了
如果需要在重载的左移运算符中访问 类的private
属性,需要在 class
中添加全局函数友元
优化后
ostream& operator<<(ostream &out, User &u) {
out << "user age:" << u.age << endl;
return out;
};
测试
cout << u << endl;
输出
user age:10
自增(++)运算符的重载
对于数字的 ++
,编译器知道该如何处理,但是对于对象的++
,编译器就不知道该如何处理了,这时候就需要重载该对象的自增运算符了
因为自增分为两种,前置自增和后置自增 (++i
)和(i++
);
class MyInt {
// 因为访问了私有成员,需要添加友元
friend ostream& operator<<(ostream& cout, MyInt n);
public:
MyInt() {
count = 0;
}
// 重载 前置++
MyInt& operator++() {
count++;
return *this;
}
// 重载 后置++ 通过占位参数来区分后置++
MyInt operator++(int) {
MyInt temp = *this;
count++;
return temp;
}
private:
int count;
};
// 这里重写 左移运算符的时候需要注意第二个参数不能写成引用,因为 后置++ 传入的不是引用,而是值
ostream& operator<<(ostream& cout, MyInt n) {
cout << n.count;
return cout;
}
void two_test3() {
MyInt n1;
// 前置++
cout << ++(++n1) << endl; // 2
cout << n1 << endl; // 2
MyInt n2;
cout << n2++ << endl; // 0
cout << n2 << endl; // 1
}
// ...
two_test3();
输出
2
2
0
1
赋值(=)运算符的重载
当我们创建一个 class
的时候,编译器默认会帮我提供一个赋值运算符,但是它内部实现的是浅拷贝,不是深拷贝
class Person4 {
public:
int* age;
Person4(int age){
this->age = new int(age);
}
// 重载 赋值运算符
Person4& operator=(Person4& p) {
if (age != NULL) {
delete age;
age = NULL;
}
age = new int(*p.age);
return *this;
}
~Person4() {
if (age != NULL) {
delete age;
age = NULL;
}
}
};
void two_test4() {
Person4 p1(10);
Person4 p2(20);
p1 = p2;
cout << *p1.age << endl;
}
输出
20
如果在上面的 class 中没有重载赋值运算符的话,编译运行的时候就会报以下的错误
Project.exe 已触发了一个断点。
关系(==、>、<)运算符的重载
重载关系运算符可以让我们 自定义 在两个对象进行比较时操作
class Person5 {
public:
string name;
int age;
Person5(string name, int age) :name(name), age(age) {};
// 重载关系运算符 ==, > < 运算符也是相似的
bool operator==(Person5& p) {
if (this->name == p.name && this->age == p.age) {
return true;
}
return false;
}
};
void two_test5() {
Person5 p1("小明", 18);
Person5 p2("小明", 18);
cout << (p1 == p2) << endl;
}
// ...
two_test5();
输出
1
函数调用运算符的重载
将类实例化出来的对象 通过函数的方式调用,叫做仿函数,仿函数没有固定写法,非常灵活
class AddNumber {
public:
int operator()(int num1, int num2) {
return num1 + num2;
}
};
void two_test6() {
AddNumber addnumber;
int num = addnumber(10, 20);
cout << num << endl;
}
// ...
two_test6();
输出
30
总结
C++
中可重载这些运算符让我们在某些情况下的编程变得更加便利,不会出现太多的不确定性。在js
中,js
引擎会根据不同的类型做不同的处理,且无法重载,以至于在前端面试题中经常出现这些js
特性衍生出来的笔试题
two_test6
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议,转载请注明出处。