玩转C++运算符重载
运算符重载语法:返回值类型 operator运算符(参数列表) { 代码逻辑。。。 }
C++中的运算符重载是通过函数来实现的,可以将重载的运算符看作是类成的一个成员函数,向普通函数一样调用。如重载String类的 + 运算符,调用的时候可以这样:
class { // ..... String operator+(const String &str) { .... } } String str1 = "hello "; String str2 = "cplusplus"; String str3 = str1.operator+(str2);从上述代码中可以看出,operator+就像是String类的一个函数,可以像普通函数一样调用,将要相加的字符串对象作为实参传递给函数即可。所以从这可以得出一个函数重载的步聚:(以上述+重载为例)
1、写出运算符的函数原型
str1.operator+(str2);
从这可以得知,+ 需要两个操作数,str1和str2(即两个字符串对象),返回值类型为String对象(加法运算后的结果)。由于是作为类的成员函数重载,所以str1在进行 + 运算时作为this指针传给函数,函数只需要一个参数即可,即被相加的字符串对象str2。
2、写出函数声明
从函数原型可以得出函数声明:String operator+(const String &str);
3、实现函数细节
String String::operator+(const String &str) { if (str.buff == nullptr) { return *this; } size_t totallen = str.len + this->len + 1; char *buff = new char[totallen]; strcpy(buff, this->buff); strcat(buff, str.buff); String temp(buff); return temp; }
下面这个示例重载了字符串操作的常用操作符:
// // String.h // C++运算符重载 // // Created by 杨信 on 14-5-8. // Copyright (c) 2014年 yangxin. All rights reserved. // #ifndef __C______String__ #define __C______String__ #include <iostream> using namespace std; class String { private: char *buff; size_t len; public: String(); // 用一个字符串初始化对象 String(const char *buff); // 拷贝构造 String(const String &str); // 析构 ~String(); // 设置字符串内容 void setString(const char *buff); // 获取字符串的长度 size_t length() const; // 获取字符串内容 char * getStr() const; // 比较两个字符串是否相等 bool operator==(String &str); // 比较两个字符串是否不相等 bool operator!=(String &str); // 比较两个字符串的大小 bool operator>(String &str); // 比较两个字符串的大小 bool operator<(String &str); // 获取或修改字符串中的某一个字符 char& operator[](int index); // 赋值构造函数 String& operator=(const String &str); // 两个字符串相加 String operator+(const String &str); // 字符串累加 String& operator+=(const String &str); // 从输入流中获取字符串 friend istream& operator>>(istream &input, String &str); // 将字符串输出到输出流 friend ostream& operator<<(ostream &output, const String &str); }; #endif /* defined(__C______String__) */ // // String.cpp // C++运算符重载 // // Created by 杨信 on 14-5-8. // Copyright (c) 2014年 yangxin. All rights reserved. // #include "String.h" #include <string> #include <cassert> #include <cmath> String::String() { this->buff = nullptr; this->len = 0; } // 用一个字符串初始化对象 String::String(const char *buff):buff(nullptr), len(0) { setString(buff); } // 拷贝构造 String::String(const String &str) { setString(str.buff); } // 析构 String::~String() { // 释放内存 if (this->buff != nullptr) { delete[] buff; buff = nullptr; len = 0; } } void String::setString(const char *buff) { if (buff == nullptr) { return; } if (this->buff != nullptr) { delete[] this->buff; this->buff = nullptr; this->len = 0; } size_t len = strlen(buff); this->buff = new char[len + 1]; this->len = len; strcpy(this->buff, buff); } // 获取字符串的长度 size_t String::length() const { return this->len; } // 获取字符串内容 char * String::getStr() const { return this->buff; } // 获取或修改字符串中的某一个字符 char& String::operator[](int index) { assert(index < this->len); return this->buff[index]; } // 比较两个字符串是否相等 bool String::operator==(String &str) { if (this->len != str.len) { return false; } for (int i = 0; i < this->len; ++i) { if (this->buff[i] != str[i]) { return false; } } return true; } // 比较两个字符串是否不相等 bool String::operator!=(String &str) { return !(*this == str); } // 比较两个字符串的大小 bool String::operator>(String &str) { char *pstr = this->buff; char *pstr2 = str.buff; while (*pstr != '\0' && *pstr2 != '\0') { if (*pstr > *pstr2) { return true; } pstr++; pstr2++; } return false; } // 比较两个字符串的大小 bool String::operator<(String &str) { return !(*this > str); } // 赋值构造函数 String& String::operator=(const String &str) { setString(str.buff); return *this; } // 两个字符串相加 String String::operator+(const String &str) { if (str.buff == nullptr) { return *this; } size_t totallen = str.len + this->len + 1; char *buff = new char[totallen]; strcpy(buff, this->buff); strcat(buff, str.buff); String temp(buff); return temp; } // 字符串累加 String& String::operator+=(const String &str) { if (str.buff == nullptr) { return *this; } // 创建一个临时缓冲区,存储对象本身的字符串和相加的字符串 size_t len = this->len + str.length(); char *temp = new char[len + 1]; strcpy(temp, this->buff); strcat(temp, str.buff); // 设置新的字符串给对象本身 setString(temp); return *this; } // 从输入流中获取字符串 istream& operator>>(istream &input, String &str) { // 在堆区创建临时缓冲区,接收用户输入 int size = 1024 * 10; char *tempbuff = new char[size]; memset(tempbuff, 0, size); // 获取用户输入 input.getline(tempbuff, size); // 将临时缓冲中的字符串保存到str对象的字符串缓冲区中 str.setString(tempbuff); // 释放临时缓冲区数据 delete[] tempbuff; tempbuff = nullptr; return input; } // 将字符串输出到输出流 ostream& operator<<(ostream &output, const String &str) { output << str.getStr(); return output; } // 测试用例 // // main.cpp // String(运算符重载) // // Created by 杨信 on 14-5-8. // Copyright (c) 2014年 yangxin. All rights reserved. // #include <iostream> #include "String.h" #include <cmath> using namespace std; int main(int argc, const char * argv[]) { // 初始化 String str1("helloz"); String str2("helloz"); // 获取字符中内容 cout << str1.getStr() << endl; // 获取字符串的长度 cout << "长度:" << str1.length() << endl; // 获取第字符串中的第一个字符 cout << "第1个字符:" << str1[0] << endl; // 比较两个字符串是否相等,相等返回1,否则返回0 bool isequal = str1 == str2; cout << isequal << endl; // 比较两个字符串的大小,str1大于str2返回1,否则返回0 cout << (str1 > str2) << endl; // 修改字符串中的第2个字符为C String s = "Hello"; s[1] = 'C'; cout << s << endl; // 测试用一个字符串去初始化另外一个字符串 String str3 = str2; cout << str3.getStr() << endl; String str4; str4 = str3; cout << str4.getStr() << endl; // 测试两个字符串相加 String str5 = str1 + str2; cout << &str5 << endl; cout << str5.getStr() << endl; // 测试字符串连等 String str6; String str7 = str6 = str5; cout << str6.getStr() << " | " << str7.getStr() << endl; // 测试字符串累加 String str8 = "i love c++ "; str8 += "i love c "; cout << str8.getStr() << endl; // 从输入流读取字符串 String str9; cout << "Please a string:"; cin >> str9; // 将字符串输出到输出流 cout << str9 << endl; return 0; }运算符重载注意事项:
- 友元函数重载运算符时需要传递所有操作数
- 成员函数重载,会将操作数本身做为this指针作为参数传入函数,如果是多元操作符,只需与它被操作的数传入函数即可
-
= 号重载时,如果对象中有新分配内存的成员,要先delete,再new,如果要支持连等操作,需要返回对象本身的引用
-
函数返回值作左值时,返回值必须为引用
- 只有C++预定义的操作符集中的操作符才可以被重载(不能自己随便写一个操作符,如:+-)
- 重载操作符不能改变操作符的优先级,例如:先乘徐,后加减
- 重载操作符不能改变操作数的个数
以下几种运算符不能被重载:
- . :成员选择运算符
- :: :作用域运算符
- * : 指针运算符
- # :预处理标志
- ?: :三目运算符,没有确定性,重载没有意义