前言
在C++语言中,官方实现的运算符可以满足我们的很多的需求,但是,为了实现我们各种各样的功能,我们不可避免的需要自己实现运算符的功能,所以,我们需要学会怎么实现运算符的重载。
C++中可以重载的运算符有
- 算术运算符:+(加法)、-(减法)、*(乘法)、/(除法)、%(取模)
- 自增和自减运算符:++(自增)、--(自减)
- 关系运算符:==(相等)、!=(不相等)、<(小于)、>(大于)、<=(小于等于)、>=(大于等于)
- 位运算符:&(按位与)、|(按位或)、^(按位异或)、~(按位取反)、<<(左移)、>> (右移)
- 逻辑运算符:&&(逻辑与)、||(逻辑或)、!(逻辑非)
- 赋值运算符:=(赋值)、+=(加赋值)、-=(减赋值)、*=(乘赋值)、/=(除赋值)、%=(取模赋值)、&=(按位与赋值)、|=(按位或赋值)、^=(按位异或赋值)、<<=(左移赋值)、>>=(右移赋值)
- 下标运算符:
- 函数调用运算符:()(函数调用)
- 成员访问运算符:->(指针成员访问)
- 类型转换运算符:type()(类型转换)
- 其他运算符:new(动态分配内存)、new[](动态分配数组)、delete(释放内存)、delete[](释放数组内存)
注意
某些运算符(例如
.和.*)无法被重载。 重载运算符时,必须遵循特定的规则和约定。
实现加法运算符(减法-,乘法*,除法/和取模%符号都一样)
#include <iostream>
class Point{
public:
Point(int x = 0, int y = 0) : x(x), y(y) {}
Point operator+(const Point& point){
return Point(x + point.x, y + point.y);
}
void PrintValue(){
std::cout << "x = " << x << ", y = " << y << std::endl;
}
void PrintOther(const Point& point){
std::cout << "x = " << point.x << ", y = " << point.y << std::endl;
}
private:
int x;
int y;
};
int main(){
Point point_1(3, 4);
Point point_2(55, 4);
Point point_3(point_1 + point_2);
point_3.PrintValue();
point_3.PrintOther(point_1);
return 0;
}
其实,当操作符的两边都有变量的话,都可以使用这种方式实现,也就是说,除了算术运算符之外,还有==(相等)、!=(不相等)、<(小于)、>(大于)、<=(小于等于)、>=(大于等于)、&(按位与)、|(按位或)、^(按位异或)、<<(左移)、>> (右移)、&&(逻辑与)、||(逻辑或)、(赋值)、+=(加赋值)、-=(减赋值)、*=(乘赋值)、/=(除赋值)、%=(取模赋值)、&=(按位与赋值)、|=(按位或赋值)、^=(按位异或赋值)、<<=(左移赋值)、>>=(右移赋值)都可以使用
我们知道,自增符号并不是操作符的两边都是变量,它只是一边有变量,代码可以这样实现
#include <iostream>
class Point{
public:
Point(int x = 0, int y = 0) : x(x), y(y) {}
//这是实现前缀加加
Point& operator++(){
x += 1;
y += 1;
return *this;
}
//后缀加加需要加一个参数,只能是int
Point& operator++(int){ //这个是为了区分前缀和后缀自增
x += 1;
y += 1;
return *this;
}
void PrintValue(){
std::cout << "x = " << x << ", y = " << y << std::endl;
}
private:
int x;
int y;
};
int main(){
Point point_1(3, 4);
//++point_1;
point_1++;
point_1.PrintValue();
return 0;
}
除了++(自增)之外,还有--(自减)、~(按位取反)、!(逻辑非)都可以使用
除了上面两种情况,那么下标运算符怎么使用呢?
#include <iostream>
#include <vector>
class CVector{
public:
CVector(){
vec = {1, 2, 3, 4};
}
int operator[](int index){
return vec[index];
}
private:
std::vector<int> vec;
};
int main(){
CVector vec;
std::cout << vec[0] << std::endl;
return 0;
}
这个代码只是让了解下标运算符怎么使用,代码没有做防御性,等你们自己做项目时,记得防御性编程
下面实现函数调用运算符(),代码如下
#include <iostream>
class Adder{
public:
int operator()(int x, int y){
return x + y;
}
};
int main(){
Adder adder;
std::cout << adder(3, 4) << std::endl;
return 0;
}
下面实现成员访问运算符->
#include <iostream>
class Adder{
public:
Adder* operator->(){
std::cout << "调用成员访问运算符->..." << std::endl;
return this;
}
void TestFunc(){
std::cout << "TestFunc()..." << std::endl;
}
};
int main(){
Adder* adder = new Adder();
adder->TestFunc();
return 0;
}
下面实现类型转换运算符,这里只实现了int和double,其他类型一样,读者可自行实现
#include <iostream>
using namespace std;
class MyClass{
public:
MyClass(int x = 0, double y = 0.0) : value(x), doubleValue(y){}
operator int() const{
return value;
}
operator double() const{
return doubleValue;
}
private:
int value;
double doubleValue;
};
int main()
{
MyClass myclass(999, 3.14);
int value = myclass;
double doubleValue = myclass;
cout << "value = " << value << ", doubleValue = " << doubleValue << endl;
return 0;
}
下面实现动态分配运算符(这个代码是笔者直接复制chatgpt的,读者可以自行实现看看)
#include <iostream>
#include <cstdlib> // 包含 malloc 和 free
class MyClass {
public:
// 重载 new 运算符
void* operator new(size_t size) {
std::cout << "自定义 new: 分配 " << size << " 字节内存" << std::endl;
void* p = std::malloc(size); // 使用 malloc 分配内存
if (!p) {
throw std::bad_alloc(); // 分配失败时抛出异常
}
return p;
}
// 重载 delete 运算符
void operator delete(void* p) {
std::cout << "自定义 delete: 释放内存" << std::endl;
std::free(p); // 使用 free 释放内存
}
// 构造函数
MyClass() {
std::cout << "构造 MyClass" << std::endl;
}
// 析构函数
~MyClass() {
std::cout << "析构 MyClass" << std::endl;
}
};
int main() {
MyClass* obj = new MyClass(); // 触发自定义 new 运算符
delete obj; // 触发自定义 delete 运算符
return 0;
}
笔者再实现一下赋值运算符
#include <iostream>
class Point{
public:
Point(int x = 0, int y = 0) : x(x), y(y) {}
Point& operator=(const Point& point){
if(&point != this){ //防止自我赋值
x = point.x;
y = point.y;
}
return *this;
}
void PrintValue(){
std::cout << "x = " << x << ", y = " << y << std::endl;
}
private:
int x;
int y;
};
int main(){
Point point_1(3, 4);
Point point_3;
point_3 = point_1;
point_3.PrintValue();
return 0;
}
除了上面的运算符,还有重载输出/输入流运算符
#include <iostream>
class Point {
public:
Point(int x = 0, int y = 0) : x(x), y(y) {}
friend std::ostream& operator<<(std::ostream& os, const Point& point) {
os << "x = " << point.x << ",y = " << point.y << std::endl;
return os;
}
friend std::istream& operator>>(std::istream& is, Point& point) {
is >> point.x >> point.y;
return is;
}
private:
int x;
int y;
};
int main() {
Point point_1(3, 4);
std::cout << point_1;
Point point_2;
std::cin >> point_2;
std::cout << point_2;
return 0;
}