首页 > 代码库 > 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 ----- 构造函数、复制控制、重载操作符