C++ 中的运算符重载(二)
运算符重载的实例和应用
运算符重载是一种非常实用和有趣的特性,它可以让我们对自定义类型的数据进行各种操作,从而实现一些复杂和高级的功能。下面我们就来介绍一些运算符重载的实例和应用,以及它们的代码和效果:
- 重载赋值运算符
=
,用于实现对象的拷贝赋值。赋值运算符=
是一种特殊的运算符,它可以对任何类型的数据进行赋值操作,即将右操作数的值赋给左操作数。但是,如果我们想要对自定义类型的数据进行赋值操作,例如类的对象,那么我们就需要重载赋值运算符=
,以便实现对象的拷贝赋值,即将右操作数对象的所有成员变量的值赋给左操作数对象的对应成员变量。这样,我们就可以实现对象的深拷贝,而不是浅拷贝,避免出现一些潜在的问题,例如内存泄漏、空指针、重复释放等。例如,我们可以定义一个String
类来表示字符串,然后重载赋值运算符=
,用于实现字符串的拷贝赋值。代码如下:
// 定义String 类
class String {
public:
// 构造函数,用于初始化字符串对象
String(const char* str = "") {
// 如果参数为空字符串,就将指针指向一个空字符,否则就动态分配内存并拷贝字符串
if (str == "") {
this->str = new char[1];
this->str[0] = '\0';
} else {
this->str = new char[strlen(str) + 1];
strcpy(this->str, str);
}
}
// 拷贝构造函数,用于初始化字符串对象
String(const String& s) {
// 动态分配内存并拷贝字符串
this->str = new char[strlen(s.str) + 1];
strcpy(this->str, s.str);
}
// 析构函数,用于释放字符串对象
~String() {
// 释放动态分配的内存
delete[] this->str;
}
// 重载赋值运算符,用于实现字符串的拷贝赋值
String& operator=(const String& s) {
// 如果左操作数和右操作数是同一个对象,就直接返回左操作数的引用,避免自赋值的错误
if (this == &s) {
return *this;
}
// 释放左操作数原有的内存
delete[] this->str;
// 动态分配新的内存并拷贝字符串
this->str = new char[strlen(s.str) + 1];
strcpy(this->str, s.str);
// 返回左操作数的引用,以便进行连续赋值
return *this;
}
// 声明友元函数,用于输出字符串对象
friend std::ostream& operator<<(std::ostream& out, const String& s);
private:
// 私有成员变量,用于存储字符串的指针
char* str;
};
// 定义友元函数,用于输出字符串对象
std::ostream& operator<<(std::ostream& out, const String& s) {
// 输出字符串的内容
out << s.str;
// 返回输出流对象,以便进行连续输出
return out;
}
// 主函数,用于测试
int main() {
// 创建两个字符串对象
String s1("Hello");
String s2("World");
// 使用赋值运算符对字符串进行拷贝赋值,并输出结果
std::cout << (s1 = s2) << std::endl; // 输出结果为:World
// 使用赋值运算符对字符串进行连续赋值,并输出结果
std::cout << (s1 = s2 = "Bing") << std::endl; // 输出结果为:Bing
return 0;
}
从上面的代码可以看出,重载赋值运算符=
可以让我们对字符串对象进行拷贝赋值,就像对内置类型的数据进行赋值一样。这样,我们就可以实现字符串对象的深拷贝,避免出现一些潜在的问题,例如内存泄漏、空指针、重复释放等。
- 重载插入运算符
<<
和提取运算符>>
,用于实现对象的输入和输出。插入运算符<<
和提取运算符>>
是两种特殊的运算符,它们可以对标准输入流std::cin
和标准输出流std::cout
进行操作,实现数据的输入和输出。但是,如果我们想要对自定义类型的数据进行输入和输出,例如类的对象,那么我们就需要重载插入运算符<<
和提取运算符>>
,以便实现对象的输入和输出,即将对象的内容输出到标准输出流,或者从标准输入流读取数据并赋给对象。这样,我们就可以实现对象的交互和显示,提高用户的体验和友好性。例如,我们可以定义一个Point
类来表示二维平面上的点,然后重载插入运算符<<
和提取运算符>>
,用于实现点的输入和输出。代码如下:
// 定义Point 类
class Point {
public:
// 构造函数,用于初始化点对象
Point(int x = 0, int y = 0) {
this->x = x;
this->y = y;
}
// 声明友元函数,用于重载插入运算符
friend std::ostream& operator<<(std::ostream& out, const Point& p);
// 声明友元函数,用于重载提取运算符
friend std::istream& operator>>(std::istream& in, Point& p);
private:
// 私有成员变量,用于存储点的横坐标和纵坐标
int x;
int y;
};
// 定义友元函数,用于重载插入运算符
std::ostream& operator<<(std::ostream& out, const Point& p) {
// 输出点的横坐标和纵坐标,用括号和逗号分隔
out << "(" << p.x << ", " << p.y << ")";
// 返回输出流对象,以便进行连续输出
return out;
}
// 定义友元函数,用于重载提取运算符
std::istream& operator>>(std::istream& in, Point& p) {
// 从输入流读取两个整数,并赋给点的横坐标和纵坐标
in >> p.x >> p.y;
// 返回输入流对象,以便进行连续输入
return in;
}
// 主函数,用于测试
int main() {
// 创建一个点对象
Point p1;
// 使用提取运算符对点进行输入,并输出结果
std::cout << "Please enter a point: ";
std::cin >> p1;
std::cout << "The point you entered is: " << p1 << std::endl;
// 例如,输入:1 2
// 输出结果为:The point you entered is: (1, 2)
return 0;
}
从上面的代码可以看出,重载插入运算符<<
和提取运算符>>
可以让我们对点对象进行输入和输出,就像对内置类型的数据进行输入和输出一样。这样,我们就可以实现点对象的交互和显示,提高用户的体验和友好性。