运算符重载是C++中的一项功能,允许用户自定义类的对象使用标准运算符(如+、-、*等)。通过运算符重载,你可以定义类对象之间的操作,使其更符合对象的语义。下面来讲讲比较常见的加号、左移、递增、赋值、关系、函数调用这六种运算符重载作用及代码示例,其它未在本文中讲过的运算符重载也应该可以通过学习本文自己推导出来。
1 加号运算符重载
当我们重载加法运算符时,我们希望能够像对待内置类型一样对待自定义类型。下面是一个简单的示例,演示如何重载加法运算符:
#include <iostream>
class MyNumber {
private:
int value;
public:
MyNumber(int val) : value(val) {}
// 重载加法运算符
// 在成员函数声明和定义的最后面加上 const 表示该成员函数是一个常量成员函数。这意味着在这个函数内部,不能修改对象的成员变量,除非这些成员变量被声明为 mutable。
MyNumber operator+(const MyNumber& other) const {
MyNumber result(value + other.value);
return result;
}
// 获取私有成员值的方法
int getValue() const {
return value;
}
};
int main() {
// 创建两个 MyNumber 对象
MyNumber num1(5);
MyNumber num2(10);
// 使用重载的加法运算符
MyNumber sum = num1 + num2;
// 显示结果
std::cout << "Sum: " << sum.getValue() << std::endl;
return 0;
}
在这个例子中,我们创建了一个 MyNumber
类,其中包含一个私有的整数成员 value
。我们重载了加法运算符 +
,使得可以直接使用 +
操作符对两个 MyNumber
对象进行相加。在 main
函数中,我们创建了两个对象 num1
和 num2
,然后使用 +
运算符将它们相加,将结果存储在 sum
中,并最终显示结果。
2 左移运算符重载
左移运算符 <<
的重载用法允许我们定义自定义类对象如何进行左移操作。这通常用于使用户定义的类对象可以与标准输出流 std::cout
一起使用。
下面是一个左移运算符重载的具体代码示例:
#include <iostream>
class MyClass {
private:
int value;
public:
MyClass(int val) : value(val) {}
// 重载左移运算符
friend std::ostream& operator<<(std::ostream& os, const MyClass& obj);
// 获取私有成员值的方法
int getValue() const {
return value;
}
};
// 左移运算符的实现
std::ostream& operator<<(std::ostream& os, const MyClass& obj) {
os << "MyClass value: " << obj.value;
return os;
}
int main() {
MyClass obj(42);
// 使用重载的左移运算符输出对象
std::cout << obj << std::endl;
return 0;
}
在这个例子中,我们定义了一个 MyClass
类,并在类外部重载了左移运算符 <<
。注意,我们将这个重载的函数声明为 friend
,这是因为它需要访问 MyClass
类的私有成员。
在 main
函数中,我们创建了一个 MyClass
对象 obj
,然后使用 std::cout << obj << std::endl;
输出该对象。由于我们重载了左移运算符,它会调用我们定义的输出函数,输出类对象的信息。
这种重载的方式使得我们可以用更自然的语法输出自定义类的对象,使其与标准输出流一起使用。
3 递增运算符重载
递增运算符 ++
的重载允许我们自定义类对象如何进行递增操作。重载递增运算符使得我们可以像操作内置类型一样对自定义对象进行递增操作。
下面是一个递增运算符 ++
的重载示例:
#include <iostream>
class Counter {
private:
int count;
public:
Counter() : count(0) {}
// 重载前缀递增运算符 ++
Counter& operator++() {
++count;
return *this;
}
// 重载后缀递增运算符 ++
Counter operator++(int) {
Counter temp(*this);
++count;
return temp;
}
// 获取计数值的方法
int getCount() const {
return count;
}
};
int main() {
Counter c1;
// 使用前缀递增运算符
++c1;
std::cout << "After prefix increment: " << c1.getCount() << std::endl;
// 使用后缀递增运算符
Counter c2 = c1++;
std::cout << "After postfix increment: " << c2.getCount() << std::endl;
return 0;
}
在这个例子中,我们定义了一个 Counter
类,然后重载了前缀递增运算符 ++
和后缀递增运算符 ++
。
-
前缀递增运算符 (++count): 该运算符返回递增后的对象的引用。它首先递增对象的计数值,然后返回递增后的对象。
-
后缀递增运算符 (count++): 该运算符返回递增前的对象的副本。它首先创建一个临时对象(副本),然后递增对象的计数值,并返回临时对象。
在 main
函数中,我们创建了一个 Counter
对象 c1
,然后使用前缀递增运算符和后缀递增运算符对其进行递增操作,并输出结果。这种重载的方式使得我们可以更灵活地使用递增运算符来操作自定义类型的对象。
4 赋值运算符重载
赋值运算符 =
的重载允许我们自定义类对象如何进行赋值操作。通过重载赋值运算符,我们可以定义类对象的复制行为,使其能够按照我们自己的方式进行赋值。
以下是一个赋值运算符 =
的重载示例:
#include <iostream>
class MyString {
private:
char* str;
public:
// 构造函数
MyString(const char* s = "") {
// 分配内存并复制字符串
str = new char[strlen(s) + 1];
strcpy(str, s);
}
// 析构函数
~MyString() {
delete[] str;
}
// 重载赋值运算符
MyString& operator=(const MyString& other) {
// 检查自赋值
if (this != &other) {
// 释放原有内存
delete[] str;
// 分配新内存并复制字符串
str = new char[strlen(other.str) + 1];
strcpy(str, other.str);
}
return *this;
}
// 获取字符串的方法
const char* getString() const {
return str;
}
};
int main() {
// 创建两个 MyString 对象
MyString str1("Hello");
MyString str2("World");
// 使用赋值运算符进行赋值
str1 = str2;
// 输出结果
std::cout << "str1: " << str1.getString() << std::endl;
std::cout << "str2: " << str2.getString() << std::endl;
return 0;
}
在这个例子中,我们定义了一个 MyString
类,它包含一个字符串 str
。我们重载了赋值运算符 =
,并在其中实现了深拷贝,以确保在赋值时动态分配的内存得到正确释放。
在 main
函数中,我们创建了两个 MyString
对象 str1
和 str2
,然后使用赋值运算符 str1 = str2
将 str2
的内容赋给了 str1
。最后,我们输出了两个对象的字符串内容。这样的重载使得我们能够使用自定义类对象进行赋值,并且确保了正确的资源管理。
5 关系运算符重载
关系运算符重载允许我们自定义类对象如何进行比较操作,例如相等性、不等性、大于、小于等。通过重载这些运算符,我们可以按照自定义的规则比较对象。
以下是一个关系运算符重载的示例,以实现自定义类对象的比较操作:
#include <iostream>
class Point {
private:
int x;
int y;
public:
// 构造函数
Point(int xCoord = 0, int yCoord = 0) : x(xCoord), y(yCoord) {}
// 重载相等运算符
bool operator==(const Point& other) const {
return (x == other.x) && (y == other.y);
}
// 重载不等运算符
bool operator!=(const Point& other) const {
return !(*this == other);
}
// 重载小于运算符
bool operator<(const Point& other) const {
return (x < other.x) || ((x == other.x) && (y < other.y));
}
// 重载大于运算符
bool operator>(const Point& other) const {
return (x > other.x) || ((x == other.x) && (y > other.y));
}
// 获取坐标的方法
int getX() const {
return x;
}
int getY() const {
return y;
}
};
int main() {
// 创建两个 Point 对象
Point p1(2, 3);
Point p2(4, 1);
// 使用关系运算符进行比较
if (p1 == p2) {
std::cout << "p1 is equal to p2" << std::endl;
} else {
std::cout << "p1 is not equal to p2" << std::endl;
}
if (p1 != p2) {
std::cout << "p1 is not equal to p2" << std::endl;
} else {
std::cout << "p1 is equal to p2" << std::endl;
}
if (p1 < p2) {
std::cout << "p1 is less than p2" << std::endl;
} else {
std::cout << "p1 is not less than p2" << std::endl;
}
if (p1 > p2) {
std::cout << "p1 is greater than p2" << std::endl;
} else {
std::cout << "p1 is not greater than p2" << std::endl;
}
return 0;
}
在这个例子中,我们定义了一个 Point
类,其中包含坐标信息。然后,我们重载了相等运算符 ==
、不等运算符 !=
、小于运算符 <
和大于运算符 >
,以允许我们对 Point
对象进行比较操作。在 main
函数中,我们创建了两个 Point
对象 p1
和 p2
,然后使用关系运算符进行比较,并输出结果。这样的重载使得我们可以按照自定义规则比较自定义类的对象。
6 函数调用运算符重载
函数调用运算符 ()
的重载允许我们使对象的实例像函数一样被调用。通过重载这个运算符,我们可以定义对象的调用行为,使其在使用括号运算符调用时执行自定义的操作。
以下是一个函数调用运算符重载的示例:
#include <iostream>
class Adder {
public:
// 重载函数调用运算符
int operator()(int a, int b) const {
return a + b;
}
};
int main() {
// 创建 Adder 对象
Adder add;
// 使用函数调用运算符
int result = add(3, 4);
// 输出结果
std::cout << "Result of add(3, 4): " << result << std::endl;
return 0;
}
在这个例子中,我们定义了一个 Adder
类,其中重载了函数调用运算符 ()
。这个运算符接受两个整数参数并返回它们的和。在 main
函数中,我们创建了一个 Adder
对象 add
,然后使用括号运算符调用它,就好像调用一个函数一样。结果会输出到标准输出流。
这种重载的方式允许我们为对象定义可调用的行为,这在某些情况下可能很有用,例如在实现函数对象时,或者在需要对对象执行某种操作时。