首页 > 代码库 > C++之重载String ----- 构造函数、复制控制、重载操作符
C++之重载String ----- 构造函数、复制控制、重载操作符
本博文 我们通过 重新实现String类 来说明构造函数,复制控制,重载操作符。
一、构造函数(包括析构函数):
1:默认构造函数;
2:用户自己定义的构造函数
注意:当用户自己定义时,也要明确显示默认构造函数,这是因为,当我们没有定义自己的构造函数时,编译器会为我们自动合成一个,而我们定义了构造函数时,编译器默认构造函数改为我们自己定义的。这时就有可能出现错误;
3:析构函数;
具体声明与实现,代码如下:
1 声明部分: 2 String(); 3 String(const char*s); //by user 4 String(const String &s); //by user 5 ~String(); 6 实现部分: 7 String::String() 8 :str_(new char[1]) 9 { *str_ = 0; }10 11 String::String(const char*s) 12 :str_(new char[strlen(s)+1])13 {14 cout << "constructed by user" << endl;15 ::strcpy(str_, s);16 }17 18 String::String(const String &s)//复制构造函数19 :str_(new char[s.size()+1])20 {21 cout << "copy" << endl;22 ::strcpy(str_, s.str_);23 }24 25 String::~String()//将delete[] 放入析构函数中是为了防止悬浮指针26 {27 cout << "~construct" << endl;28 delete[] str_; 29 }
二、复制控制(见上个博文);
三:重载运算符;
1)、 输入输出:
由于 输入输出流不可复制也不能复制,因此,形参和返回值只能为 引用 类型。
注意:为了与io标准库一致,操作符应接受i/ostream&作为第一个形参,对类类型const对象的引用作为第二个形参,并返回对 i/ostream 形参的引用。
输入时,要注意检查输入的内容是否合法;(注意inline的作用)
具体声明与实现 如以下代码:
声明:friend std::ostream &operator<<(std::ostream &os, const String &s);friend std::istream &operator>>(std::istream &is, String &s);实现:inline std::ostream &operator<<(std::ostream &os, const String &s){ os << s.str_ ; return os;//no copy, no assignment;return reference}inline std::istream &operator>>(std::istream &is, String &s){ char tmp[1024]; if(is >> tmp)//注意要检查错误 s.str_ = tmp; return is;}
2)、赋值操作符与复合赋值操作符的重载:
赋值操作符 = 必须是类的成员函数。
一般而言, = 、+= 应返回做操作数的引用。
具体声明与实现如下代码:
1 声明: 2 String& operator=(const char*s); 3 String& operator=(const String &s); 4 String& operator+=(const char*s); 5 String& operator+=(const String &s); 6 实现: 7 //赋值时必须判断左右操作数是否相同;否则delete[]将会把“自己”删除 8 String& String::operator=(const char*s) 9 {10 cout << "assignment" << endl;11 if(str_ != s) 12 {13 delete[] str_;14 str_ = new char[strlen(s)+1];15 ::strcpy(str_ ,s);16 }17 return *this; 18 }19 20 String& String::operator=(const String &s)21 {22 cout << "assignment" << endl;23 if(this != &s)//attention24 {25 delete[]str_;26 str_ = new char[s.size()+1];27 ::strcpy(str_, s.str_);28 }29 return *this;30 }31 //复合赋值的步骤:32 //产生一个临时变量,将左右操作数复制于其中;33 //删除原来的成员, 将临时变量copy至成员中34 String& String::operator+=(const char*s)35 {36 cout <<"complex assignment" << endl;37 char *st = new char[size()+strlen(s) +1];38 ::strcpy(st, str_);39 ::strcat(st, s);40 41 delete[]str_;//attention42 str_ = st ;43 44 return *this;45 }46 String& String::operator+=(const String &s)47 {48 cout << "complex assignment" << endl;49 char *st = new char[size()+s.size()+1];50 ::strcpy(st, str_);51 ::strcat(st, s.str_);52 53 delete[]str_;//attention54 str_ = st ;55 56 return *this;57 }
3)、加法运算符(+):
我们最好将 + 运算符声明为friend函数,因为若果声明为成员函数,则第一个参数 默认为本对象,这就可能限制 + 运算符的作用范围。
注意:这里我们用上述的 += 实现 +,这样可以不必 创建和赊销一个临时变量来保存+ 的结果;加法操作符不改变操作数的状态,所以我们将 操作数声明为 const对象的引用, 而 它产生并返回一个新的对象,该对象初始化为 第一个参数 const String &s1的副本。
实现如下:
1 声明; 2 friend String operator+(const String &s1, const String &s2); 3 friend String operator+(const String &s1, const char *str); 4 friend String operator+(const char *str , const String &s1); 5 实现: 6 String operator+(const String &s1, const String &s2) 7 { 8 String s(s1); 9 s += s2;10 return s;11 }12 13 String operator+(const String &s1, const char *str)14 {15 String s(s1);16 s += str;17 return s;18 }19 20 String operator+(const char *str, const String &s1)21 {22 String s(s1);23 s += str;24 return s;25 }
4)、关系运算符:
实现如下:
1 声明: 2 friend bool operator>(const String &s1, const String &s2); 3 friend bool operator>=(const String &s1, const String &s2); 4 friend bool operator<(const String &s1, const String &s2); 5 friend bool operator<=(const String &s1, const String &s2); 6 friend bool operator==(const String &s1, const String &s2); 7 friend bool operator!=(const String &s1, const String &s2); 8 实现: 9 bool operator>(const String &s1, const String &s2)10 {11 return ::strcmp(s1.str_, s2.str_)>0 ;12 }13 bool operator>=(const String &s1, const String &s2)14 {15 return !(s1 < s2);16 }17 bool operator<(const String &s1, const String &s2)18 {19 return !((s1 > s2)|| s1 == s2);20 }21 bool operator<=(const String &s1, const String &s2)22 {23 return !(s1 > s2) ;24 }25 bool operator==(const String &s1, const String &s2)26 {27 return ::strcmp(s1.str_, s2.str_)==0;28 }29 bool operator!=(const String &s1, const String &s2)30 {31 return !(s1 == s2);
5)、下标操作符 与 swap函数
下标操作符 最好 重载两个,因为 String 有 非const 和 const型。
而const型 是不允许修改的。
1 声明: 2 void swap(String &other); 3 char &operator[](size_t index); 4 const char operator[](size_t index)const; 5 6 size_t size()const 7 { return strlen(str_); } 8 const char *c_str()const 9 { return str_; }10 实现:11 char &String::operator[](size_t index)12 {13 return str_[index];14 }15 16 const char String::operator[](size_t index)const17 {18 return str_[index];19 }20 21 void String::swap(String &other)22 {23 std::swap(str_, other.str_);
完整代码如下:
1 //String.h 2 #ifndef STRING_H_ 3 #define STRING_H_ 4 5 #include <iostream> 6 #include <string.h> 7 8 //含有指针的类 9 class String10 {11 friend std::ostream &operator<<(std::ostream &os, const String &s);12 friend std::istream &operator>>(std::istream &is, String &s);13 friend String operator+(const String &s1, const String &s2); 14 friend String operator+(const String &s1, const char *str); 15 friend String operator+(const char *str , const String &s1); 16 friend bool operator>(const String &s1, const String &s2);17 friend bool operator>=(const String &s1, const String &s2);18 friend bool operator<(const String &s1, const String &s2);19 friend bool operator<=(const String &s1, const String &s2);20 friend bool operator==(const String &s1, const String &s2);21 friend bool operator!=(const String &s1, const String &s2);22 public:23 String();24 String(const char*s); //by user25 String(const String &s); //by user26 ~String();27 28 String& operator=(const char*s);29 String& operator=(const String &s);30 String& operator+=(const char*s);31 String& operator+=(const String &s);32 33 void swap(String &other);34 char &operator[](size_t index);35 const char operator[](size_t index)const;36 37 size_t size()const38 { return strlen(str_); }39 40 const char *c_str()const41 { return str_; }42 43 void print()const;44 45 private:46 char *str_;47 };48 inline std::ostream &operator<<(std::ostream &os, const String &s)49 {50 os << s.str_ ;51 return os;//no copy, no assignment;return reference52 }53 inline std::istream &operator>>(std::istream &is, String &s)54 {55 char tmp[1024];56 if(is >> tmp)//注意要检查错误57 s.str_ = tmp;58 return is;59 }60 61 #endif
String.cpp:
1 //String.cpp 2 #include "String.h" 3 4 #include <string.h> 5 #include <iostream> 6 using namespace std; 7 8 String::String() 9 :str_(new char[1]) 10 { *str_ = 0; } 11 12 String::String(const char*s) 13 :str_(new char[strlen(s)+1]) 14 { 15 cout << "constructed by user" << endl; 16 ::strcpy(str_, s); 17 } 18 19 String::String(const String &s)//复制构造函数 20 :str_(new char[s.size()+1]) 21 { 22 cout << "copy" << endl; 23 ::strcpy(str_, s.str_); 24 } 25 26 String::~String()//将delete[] 放入析构函数中是为了防止悬浮指针 27 { 28 cout << "~construct" << endl; 29 delete[] str_; 30 } 31 //赋值时必须判断左右操作数是否相同;否则delete[]将会把“自己”删除 32 String& String::operator=(const char*s) 33 { 34 cout << "assignment" << endl; 35 if(str_ != s) 36 { 37 delete[] str_; 38 str_ = new char[strlen(s)+1]; 39 ::strcpy(str_ ,s); 40 } 41 return *this; 42 } 43 44 String& String::operator=(const String &s) 45 { 46 cout << "assignment" << endl; 47 if(this != &s)//attention 48 { 49 delete[]str_; 50 str_ = new char[s.size()+1]; 51 ::strcpy(str_, s.str_); 52 } 53 return *this; 54 } 55 56 //复合赋值的步骤: 57 //产生一个临时变量,将左右操作数复制于其中; 58 //删除原来的成员, 将临时变量copy至成员中 59 String& String::operator+=(const char*s) 60 { 61 cout <<"complex assignment" << endl; 62 char *st = new char[size()+strlen(s) +1]; 63 ::strcpy(st, str_); 64 ::strcat(st, s); 65 66 delete[]str_;//attention 67 str_ = st ; 68 69 return *this; 70 } 71 String& String::operator+=(const String &s) 72 { 73 cout << "complex assignment" << endl; 74 char *st = new char[size()+s.size()+1]; 75 ::strcpy(st, str_); 76 ::strcat(st, s.str_); 77 78 delete[]str_;//attention 79 str_ = st ; 80 81 return *this; 82 } 83 84 String operator+(const String &s1, const String &s2) 85 { 86 String s(s1); 87 s += s2; 88 return s; 89 } 90 91 String operator+(const String &s1, const char *str) 92 { 93 String s(s1); 94 s += str; 95 return s; 96 } 97 98 String operator+(const char *str, const String &s1) 99 {100 String s(s1);101 s += str;102 return s;103 }104 105 106 107 bool operator>(const String &s1, const String &s2)108 {109 return ::strcmp(s1.str_, s2.str_)>0 ;110 }111 bool operator>=(const String &s1, const String &s2)112 {113 return !(s1 < s2);114 }115 bool operator<(const String &s1, const String &s2)116 {117 return !((s1 > s2)|| s1 == s2);118 }119 bool operator<=(const String &s1, const String &s2)120 {121 return !(s1 > s2) ;122 }123 bool operator==(const String &s1, const String &s2)124 {125 return ::strcmp(s1.str_, s2.str_)==0;126 }127 bool operator!=(const String &s1, const String &s2)128 {129 return !(s1 == s2);130 }131 132 char &String::operator[](size_t index)133 {134 return str_[index];135 }136 137 const char String::operator[](size_t index)const138 {139 return str_[index];140 }141 142 void String::swap(String &other)143 {144 std::swap(str_, other.str_);145 }146 void String::print()const147 {148 cout << str_ << endl;149 }
main.cpp:
1 #include "String.h" 2 #include <iostream> 3 #include <string.h> 4 #include <assert.h> 5 #include <unistd.h> 6 using namespace std; 7 8 int main(int argc, const char *argv[]) 9 {10 String s;11 s.print();12 13 String s2("hello");14 s2.print();15 cout <<s2.size() << endl;16 cout << s2.c_str() << endl;17 /* 18 String s3;19 cin >> s3;20 cout << s3 << endl; //munmap_chunk()->invalid pointer21 */ 22 String s4; //String s4 = "hello world" init23 s4 = "hello world";24 cout << s4 << endl;25 26 String s5;27 s5 = s4 ;28 cout << s5 << endl;29 30 assert(s5 == s4);31 assert(s5 != s2);32 assert(s5 >= s2);33 assert(s5 > s2);34 assert(s2 < s5);35 assert(s2 <= s5);36 37 String t1 ;38 t1 = "beij";39 t1 += "shangh";40 cout << t1 << endl;41 42 String t2;43 t2 = "shenzh";44 t1 += t2 ;45 cout << t1 << endl;46 47 t1[0]= ‘A‘;48 cout << t1 << endl;49 /* 50 const String t3 ="wnager"; // error const->k51 t3[0]=‘l‘;52 cout << t3 << endl;53 */ 54 String u1 ,u2;55 u1 = s2;56 u2 = "wow";57 58 u1 = u2 + " my god";59 cout << u1 << endl;60 61 u1 = t2 + u2 ;62 cout << u1 << endl;63 64 cout << "before:" ;65 cout << s4 << " " << u2 << endl;66 67 cout << "swap"<< endl;68 u2.swap(s4);69 cout << "after:"; 70 cout << s4 << " " << u2 << endl;71 72 return 0;73 }
测试结果如下:
1 //test result 2 test@ubuntu:~/xiaofei/0926overloading$ ./a.out 3 4 constructed by user 5 hello 6 5 7 hello 8 assignment 9 hello world10 assignment11 hello world12 assignment13 complex assignment14 beijshangh15 assignment16 complex assignment17 beijshanghshenzh18 Aeijshanghshenzh19 assignment20 assignment21 copy22 complex assignment23 assignment24 ~construct25 wow my god26 copy27 complex assignment28 assignment29 ~construct30 shenzhwow31 before:hello world wow32 swap33 after:wow hello world34 ~construct35 ~construct36 ~construct37 ~construct38 ~construct39 ~construct40 ~construct41 ~construct
C++之重载String ----- 构造函数、复制控制、重载操作符