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)//attention
24     {
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_;//attention
42     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_;//attention
54     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)const
17 {
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 String
10 {
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 user
25         String(const String &s); //by user
26         ~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()const
38         { return strlen(str_); }
39 
40         const char *c_str()const
41         { 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 reference
52 }
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)const
138 {
139     return str_[index];
140 }
141 
142 void String::swap(String &other)
143 {
144     std::swap(str_, other.str_);
145 }
146 void String::print()const
147 {
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 pointer
21 */    
22     String s4;   //String s4 = "hello world" init
23     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->k
51     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 world
10 assignment
11 hello world
12 assignment
13 complex assignment
14 beijshangh
15 assignment
16 complex assignment
17 beijshanghshenzh
18 Aeijshanghshenzh
19 assignment
20 assignment
21 copy
22 complex assignment
23 assignment
24 ~construct
25 wow my god
26 copy
27 complex assignment
28 assignment
29 ~construct
30 shenzhwow
31 before:hello world  wow
32 swap
33 after:wow  hello world
34 ~construct
35 ~construct
36 ~construct
37 ~construct
38 ~construct
39 ~construct
40 ~construct
41 ~construct