C++ Primer 学习笔记_31_操作符重载与转换(2)--++/--运算符重载、!运算符重载、赋值运算符重载 、String类([]、 +、 += 运算符重载)、>>和<<运算符重载
1、前置++运算符重载
成员函数的方式重载,原型为:
函数类型 & operator++();
友元函数的方式重载,原型为:(一般以友元方式重载会多一个参数)
friend 函数类型 & operator++(类类型 &);
2、后置++运算符重载(为了区分前置和后置,在后置++中多了一个参数int,没有实际作用)
成员函数的方式重载,原型为:
函数类型 operator++(int);
友元函数的方式重载,原型为:
friend 函数类型 operator++(类类型 &, int);
3、前置--运算符重载
成员函数的方式重载,原型为:
函数类型 & operator--();
友元函数的方式重载,原型为:
friend 函数类型 & operator--(类类型 &);
4、后置--运算符重载
成员函数的方式重载,原型为:
函数类型 operator--(int);
友元函数的方式重载,原型为:
friend 函数类型 operator--(类类型 &, int);
//Integer.h #ifndef _INTEGER_H_ #define _INTEGER_H_ class Integer { public: Integer(int n); ~Integer(); Integer &operator++(); //friend Integer& operator++(Integer& i); Integer operator++(int n); //friend Integer operator++(Integer& i, int n); Integer &operator--(); //friend Integer& operator--(Integer& i); Integer operator--(int n); //friend Integer operator--(Integer& i, int n); void Display() const; private: int n_; }; #endif // _INTEGER_H_
//Integer.cpp #include "Integer.h" #include <iostream> using namespace std; Integer::Integer(int n) : n_(n) { } Integer::~Integer() { } Integer& Integer::operator++() { ++n_; return *this; } //Integer& operator++(Integer& i) //一般以友元方式重载会多一个参数 //{ // ++i.n_; // return i; //} Integer Integer::operator++(int n) //要返回临时对象,因此不能返回引用 { //后置++有所不同,写法和前置++不同,应该创建一个还未++的临时对象,并返回它 Integer tmp(n_); n_++; return tmp; } //Integer operator++(Integer& i, int n) //{ // Integer tmp(i.n_); // i.n_++; // return tmp; //} Integer& Integer::operator--() { --n_; return *this; } //Integer& operator--(Integer& i) //{ // --i.n_; // return i; //} Integer Integer::operator--(int n) { //n_--; Integer tmp(n_); n_--; return tmp; } //Integer operator--(Integer& i, int n) //{ // Integer tmp(i.n_); // i.n_--; // return tmp; //} void Integer::Display() const { cout << n_ << endl; }
//main.cpp #include "Integer.h" #include <iostream> using namespace std; int main(void) { Integer n(100); n.Display(); cout << "++阶段" << endl; Integer n2 = ++n; n.Display(); n2.Display(); Integer n3 = n++; n.Display(); n3.Display(); cout << "--阶段" << endl; Integer m(100); Integer m2 = --m; m.Display(); m2.Display(); Integer m3 = m--; m.Display(); m3.Display(); return 0; }
解释:需要注意的是为了区别于前置++,后置++多了一个int 参数,但实际上是没作用的,设置断点调试的时候可以发现默认赋值为0。而且此时成员函数不能与友元函数共存,因为调用++运算符时不明确。
二、赋值运算符重载、!运算符重载
1、示例
//String.h #ifndef _STRING_H_ #define _STRING_H_ class String { public: explicit String(const char* str=""); //将转换构造函数加上explicit,没有办法进行转换构造 String(const String& other); String& operator=(const String& other); String& operator=(const char* str); bool operator!() const; ~String(void); void Display() const; private: char* AllocAndCpy(const char* str); char* str_; }; #endif // _STRING_H_
//String.cpp #pragma warning(disable:4996) #include "String.h" #include <string.h> #include <iostream> using namespace std; String::String(const char* str) { str_ = AllocAndCpy(str); } String::String(const String& other) { str_ = AllocAndCpy(other.str_); } String& String::operator=(const String& other) { if (this == &other) //避免自身赋值给自身,s1 = s1 return *this; delete[] str_; //调用拷贝构造函数一般还没有str_,所以直接创建。但是调用operator=,已经存在,需要delete str_ = AllocAndCpy(other.str_); return *this; } String& String::operator=(const char* str) { delete[] str_; str_ = AllocAndCpy(str); return *this; } bool String::operator!() const //字符串非空返回true,字符串空返回false { return strlen(str_) != 0; } String::~String() { delete[] str_; } char* String::AllocAndCpy(const char* str) { int len = strlen(str) + 1; char* newstr = new char[len]; memset(newstr, 0, len); strcpy(newstr, str); return newstr; } void String::Display() const { cout << str_ << endl; }
//main.cpp #include "String.h" #include <iostream> using namespace std; int main(void) { String s1("abc"); String s2(s1); //调用拷贝构造函数 String s3; s3 = s1; //调用赋值运算符 s3.Display(); s3 = "xxxx"; //由于声明了explicit,不能转换,因此也需要重载operator=(const char* str) s3.Display(); String s4; bool notempty; notempty = !s4; cout << notempty << endl; s4 = "aaaa"; notempty = !s4; cout << notempty << endl; return 0; }
解释:假设有三个对象,str1,str2,str3,在程序中语句str1=str2=str3将不能通过编译。!运算符这里指当字符串不为空时为真。
7、示例
//String.h #ifndef _STRING_H_ #define _STRING_H_ #include <iostream> using namespace std; class String { public: String(const char* str=""); String(const String& other); String& operator=(const String& other); String& operator=(const char* str); bool operator!() const; char& operator[](unsigned int index); const char& operator[](unsigned int index) const; friend String operator+(const String& s1, const String& s2); String& operator+=(const String& other); friend ostream& operator<<(ostream& os, const String& str); friend istream& operator>>(istream& is, String& str); ~String(void); void Display() const; private: String& Assign(const char* str); char* AllocAndCpy(const char* str); char* str_; }; #endif // _STRING_H_
//String.cpp #pragma warning(disable:4996) #include "String.h" #include <string.h> //#include <iostream> //using namespace std; String::String(const char* str) { str_ = AllocAndCpy(str); } String::String(const String& other) { str_ = AllocAndCpy(other.str_); } String& String::operator=(const String& other) { if (this == &other) return *this; return Assign(other.str_); } String& String::operator=(const char* str) { return Assign(str); } String& String::Assign(const char* str) { delete[] str_; str_ = AllocAndCpy(str); return *this; } bool String::operator!() const { return strlen(str_) != 0; } char& String::operator[](unsigned int index) //因为[]函数返回引用,因此[]可以出现在表达式的左边 { //return str_[index]; //应该让non const 版本调用 const版本 return const_cast<char&>(static_cast<const String&>(*this)[index]); //const_cast去掉常量性,static_cast转换成为const } const char& String::operator[](unsigned int index) const { return str_[index]; } String::~String() { delete[] str_; } char* String::AllocAndCpy(const char* str) { int len = strlen(str) + 1; char* newstr = new char[len]; memset(newstr, 0, len); strcpy(newstr, str); return newstr; } void String::Display() const { cout << str_ << endl; } String operator+(const String& s1, const String& s2) { //int len = strlen(s1.str_) + strlen(s2.str_) + 1; //char* newstr = new char[len]; //memset(newstr, 0, len); //strcpy(newstr, s1.str_); //strcat(newstr, s2.str_); //String tmp(newstr); //delete newstr; //return tmp; String str = s1; str += s2; //因为前面注释的代码跟+=的内容差不多 return str; } String& String::operator+=(const String& other) { int len = strlen(str_) + strlen(other.str_) + 1; char* newstr = new char[len]; memset(newstr, 0, len); strcpy(newstr, str_); strcat(newstr, other.str_); delete[] str_; str_ = newstr; return *this; } ostream& operator<<(ostream& os, const String& str) { os << str.str_; return os; } istream& operator>>(istream& is, String& str) { char tmp[1024]; cin >> tmp; str = tmp; return is; }
//main.cpp #include "String.h" #include <iostream> using namespace std; int main(void) { String s1("abcdefg"); char ch = s1[2]; cout << ch << endl; s1[2] = 'A'; //因为[]函数返回引用,因此[]可以出现在表达式的左边 s1.Display(); const String s2("xyzabc"); ch = s2[2]; //s2[2] = 'M'; s2.Display(); String s3 = "xxx"; String s4 = "yyy"; String s5 = s3 + s4; s5.Display(); String s6 = "aaa" + s3 + "sdfadfa" + "xxxx"; //在做加法运算的时候,前两个至少有一个是对象 s6.Display(); s3+=s4; s3.Display(); cout << s3 << endl; String s7; cin >> s7; cout << s7 << endl; return 0; }
运行结果:
参考:
C++ primer 第四版