zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    Go语言实战_自己定义OrderedMap
    计算机图形学(二)输出图元_3_画线算法_2_DDA算法
    hibernate---java.lang.UnsupportedOperationException: The user must supply a JDBC connection
    OpenCV从入门到放弃(五):像素!
    ibatis 开发中的经验 (三)Struts+Spring+Ibatis 开发环境搭建
    HDU4911-Inversion
    hdu
    Maximum Likelihood Method最大似然法
    最小二乘法least square
    PASCAL VOC数据集The PASCAL Object Recognition Database Collection
  • 原文地址:https://www.cnblogs.com/xfxu/p/3999315.html
Copyright © 2011-2022 走看看