zoukankan      html  css  js  c++  java
  • 字符串类——字符串类的创建(上)

    1,历史遗留问题:

           1,C 语言不支持真正意义上的字符串;

           2,C 语言用字符数组和一组函数实现字符串操作;

                  1,字符数组模拟字符串;

                  2,字符数组以 来结束就是合法字符串;

                  3,C 语言中没有单独类型支持字符串,要么是字符数组,要么是 char* 指针;

           3,C 语言不支持自定义类型,因此无法获得字符串类型;

          

    2,从 C 到 C++ 的进化过程引入了自定义类型;

         在 C++ 中可以通过类完成字符串类型的定义;

         C++ 中的原生类型不包含字符串类型,要兼容 C 语言;

      

    3,C++ 中通过库来支持字符串类型:

           1,stl 中就有 string 类,这是官方承认的 string 类型;

        2,Qt 中提供 QString;

        3,MFC 中提供 CString;

      

    4,数据结构库中也应该包含字符串库,否则拿出去应该没人使用的,本文就是设计自己的 String 类;

    5,DTLib 中字符串类的设计:

     

           1,所以字符串类的设计方案基本一致,只不过是出自不同厂商,对应的类型不同,在对应的类型下面使用设计的方法确是一样的;

           2,继承自 Object,依赖 C 语言关于字符串函数的一个包(函数集);

           3,要注意设计的成员函数的先后秩序;

          

    6,DTLib 中字符串类的实现(本博文中实现了包括KMP算法应用在内的一系列字符串功能函数,包括后续“字符串类——字符串类的创建(下)”、“字符串类———KMP子串查找算法”、“字符串类——KMP算法的应用”博文中的内容,不限于下图):

     

          

    7,实现时的注意事项:

           1,无缝实现 String 对象与 char* 字符串的互操作;

           2,操作符重载函数需要考虑是否支持 const 版本;

           3,通过 C 语言中的字符串函数实现 String 的成员函数;

          

    8,C 语言中的字符串类型:

           1,常量字符串:

                  1,const char* string,string 指向字符数组首地址;

                  2,char string[],string[] 为字符数组;

           2,即要么是字符串数组本身,要么是指向字符数组首地址(一般的是这样)的 char*;

           3,本质还是字符数组;

    9,字符串类 String 的实现:

      1,String.h 的实现:

      1 #ifndef DTSTRING_H
      2 #define DTSTRING_H
      3 
      4 #include "Object.h"
      5 
      6 namespace DTLib
      7 {
      8 
      9 class String : public Object // 库规则中每个类都要继承自顶层父类 Object
     10 {
     11 protected:   // 面相对象的技术封装 C 语言中的字符串实现。
     12     char* m_str;  // 指向字符串,字符串的表现形式是字符数组;
     13    int m_length;  // 当前字符串的长度;
     14 
     15     void init(const char* s);  // 初始化函数
     16     /* 比对函数,为 startWith() 服务,前两个参数为字符数组的首地址,第三个参数是字符数组长度;长度范围内字符数组对应元素都相等,返回真; */
     17     bool equal(const char* l, const char* r, int len) const;
     18     static int* make_pmt(const char* p);
     19    static int kmp(const char* s, const char* p);
     20 
     21 public:
     22     String();
     23     String(char c);
     24     String(const char* s);
     25    String(const String& s); //  拷贝构造函数;
     26 
     27     int length() const;  // 得到字符串长度;
     28    const char* str()  const; // 字符串对象与传统字符串进行互操作的转换函数
     29 
     30     /* 判断当前的字符对象是否以 s 开头,判断当前的字符对象是否以 s 结束 */
     31     bool startWith(const char* s) const;
     32     bool startWith(const String& s) const;
     33     bool endOf(const char* s) const;
     34    bool endOf(const String& s) const;
     35 
     36     /* 将字符串 s 插入到对象下标为 i 处,返回 String& 是为了链式操作,返回字符串自己 */
     37     String& insert(int i, const char* s);
     38    String& insert(int i, const String& s);
     39 
     40     /* 去掉字符串中的空格 */
     41    String& trim();
     42 
     43     int indexOf(const char* ) const;
     44    int indexOf(const String& s) const;
     45 
     46     /* 删除字符串中的子串 s */
     47     String& remove(int i, int len); // 删除下标 i 处指定长度 len 的长度;
     48     String& remove(const char* s);
     49    String& remove(const String& s);
     50 
     51     /* 用 s 替换字符串中的 t */
     52     String& replace(const char* t, const char* s);
     53     String& replace(const String& t, const char* s);
     54     String& replace(const char* t, const String& s);
     55    String& replace(const String& t, const String& s);
     56 
     57     /* 提取以 i 为起点去长度为 len 的子串 */
     58    String sub(int i, int len) const; // 因为这里不会改变当前字符串状态,所以为 const 成员函数;
     59 
     60     /* 字符串对象应该能够像字符数组一样,通过每一个下标来访问每一个字符; */
     61     char& operator [] (int i); // 引用意味着可以被赋值,可以出现在赋值符号左边(此时是对象),给没有被 const 修饰的版本用;
     62    char operator [] (int i) const;  // 不能作为左值,所以不能返回引用对象;给 const 修饰的常对象版本使用
     63 
     64     /* 比较操作符重载函数,兼容字符串对象与 C 语言中 const char* 所代表的字符串中的逻辑操作;封装 strcmp 函数完成 ;const 版本给被 const 修饰的常对象使用的,未被 const 修饰的对象也可以作为参数被调用;*/
     65     bool operator == (const String& s) const;
     66     bool operator == (const char* s) const;
     67     bool operator != (const String& s) const;
     68     bool operator != (const char* s) const;
     69     bool operator > (const String& s) const;
     70     bool operator > (const char* s) const;
     71     bool operator < (const String& s) const;
     72     bool operator < (const char* s) const;
     73     bool operator >= (const String& s) const;
     74     bool operator >= (const char* s) const;
     75     bool operator <= (const String& s) const;
     76    bool operator <= (const char* s) const;
     77 
     78     
     79    /* 加法操作符重载函数 */
     80     String operator + (const String& s) const;
     81     String operator + (const char* s) const;
     82     String& operator += (const String& s); 
     83    String& operator += (const char* s);
     84 
     85     /* 减法操作符重载函数 */
     86     String operator - (const String& s) const;
     87     String operator - (const char* s) const;
     88     String& operator -= (const String& s);  //成员会改变的,所以不能用const修饰了
     89    String& operator -= (const char* s);
     90 
     91     /* 赋值操作符重载函数 */
     92     String& operator = (const String& s);
     93     String& operator = (const char* s);
     94    String& operator = (char c);  // 加上一个字符
     95 
     96     ~String();
     97 };
     98 
     99 }
    100 
    101 #endif // DTSTRING_H

     2,String.cpp 的实现:

      1 #include <cstring>
      2 #include <cstdlib>
      3 #include "DTString.h"
      4 #include "Exception.h"
      5 
      6 using namespace std;
      7 namespace DTLib
      8 {
      9 
     10 /* 建立指定字符串的 pmt(部分匹配表)表 */
     11 int* String::make_pmt(const char* p)  //  O(m),只有一个 for 循环
     12 {
     13     int len = strlen(p);
     14    int* ret = static_cast<int*>(malloc(sizeof(int) * len));
     15 
     16     if ( ret != NULL )
     17     {
     18         int ll = 0; //定义 ll,前缀和后缀交集的最大长度数,largest length;第一步
     19         ret[0] = 0;  // 长度为 1 的字符串前后集都为空,对应 ll 为 0;
     20         for(int i=1; i<len; i++)  // 从第一个下标,也就是第二个字符开始计算,因为第 0 个字符前面已经计算过了; 第二步
     21         {
     22             /* 算法第四步 */
     23             while( (ll > 0) && (p[ll] != p[i]) ) // 当 ll 值为零时,转到下面 if() 函数继续判断,最后赋值与匹配表,所以顺序不要错;
     24             {
     25                 ll = ret[ll - 1];  // 从之前匹配的部分匹配值表中,继续和最后扩展的那个字符匹配
     26             }
     27 
     28             /* 算法的第三步,这是成功的情况 */
     29             if( p[ll] == p[i] ) // 根据 ll 来确定扩展的种子个数为 ll,而数组 ll 处就处对应的扩展元素,然后和最新扩展的元素比较;
     30             {
     31                 ll++;   // 若相同(与假设符合)则加一
     32             }
     33 
     34             ret[i] = ll;   // 部分匹配表里存储部分匹配值 ll
     35         }
     36    }
     37 
     38     return ret;
     39 }
     40 
     41 /* 在字符串 s 中查找子串 p */
     42 int String::kmp(const char* s, const char* p)  // O(m) + O(n) ==> O(m+n), 只有一个 for 循环
     43 {
     44     int ret = -1;
     45     int sl = strlen(s);
     46     int pl = strlen(p);
     47    int* pmt = make_pmt(p);
     48 
     49     if( (pmt != NULL) && (0 < pl) && (pl <= sl) ) // 判断查找条件
     50     {
     51         for(int i=0, j=0; i<sl; i++)  // i 的值要小于目标窜长度才可以查找
     52         {
     53             while( (j > 0) && (s[i] != p[j]) ) // 比对不上的时候,持续比对,
     54             {
     55                 j = pmt[j-1];  //移动后应该继续匹配的位置,j =j-(j-LL)= LL = PMT[j-1]
     56             }
     57 
     58             if( s[i] == p[j] )  // 比对字符成功
     59             {
     60                 j++;   // 加然后比对下一个字符
     61             }
     62 
     63             if( j == pl )  // 这个时候是查找到了,因为 j 增加到了 pl 的长度;
     64             {
     65                 ret = i + 1 - pl; // 匹配成功后,i 的值停在最后一个匹配成功的字符上,这样就返回匹配成功的位置
     66                 break;
     67             }
     68         }
     69    }
     70 
     71    free(pmt);
     72 
     73     return ret;
     74 }
     75 
     76 /* 通过参数 s,具体产生当前字符串对象当中的数据,供构造函数使用;实现的方法就是封装 */
     77 void String::init(const char* s)
     78 {
     79    m_str = strdup(s);  // 当前字符串当中的数据通过 m_str 指针指向;
     80 
     81     if( m_str )  // 复制失败会返回空指针;
     82     {
     83         m_length = strlen(m_str);  // 获取长度;
     84     }
     85     else
     86     {
     87         THROW_EXCEPTION(NoEnoughMemoryException, "No memory to creat String object ...");
     88     }
     89 }
     90 
     91 /* 比对函数,为 startWith() 服务,前两个参数为字符数组的首地址,第三个参数是字符数组长度;长度范围内字符数组对应元素都相等,返回真; */
     92 bool String::equal(const char* l, const char* r, int len) const
     93 {
     94     bool ret = true;
     95     for(int i=0; i<len && ret; i++)  // 这里的 ret 看似没用,实则只要有元素不相等就停止循环、非常重要;
     96     {
     97         ret = ret && (l[i] == r[i]);  // 如果有一个位置的字符不相等,则结束比较,返回 false;
     98    }
     99 
    100     return ret;
    101 }
    102 
    103 String::String()
    104 {
    105     init("");
    106 }
    107 
    108 String::String(const char* s)
    109 {
    110     init(s ? s : ""); // 将空指针转换为空字符串,s 正确了返回 s,错误了返回 “”(这是空字符串)
    111 }
    112 
    113 String::String(const String& s)
    114 {
    115     init(s.m_str);
    116 }
    117 
    118 /* 字符作为初始值创建字符串对象 */
    119 String::String(char c)
    120 {
    121     char s[] = {c, ''};  // 用字符数组模拟字符串的初始化方式,这是两种初始化中的一种;
    122     init(s);
    123 }
    124 
    125 int String::length() const
    126 {
    127     return m_length;
    128 }
    129 
    130 /* 字符串对象与传统字符串进行互操作的转换函数 */
    131 const char* String::str() const  // 直接返回字符串首地址
    132 {
    133     return m_str; // 字符串对象本身就是通过字符指针来指向的,这样就可以直接转换;
    134 }
    135 
    136 /* 判断当前的字符对象是否以 s 开头 */
    137 bool String::startWith(const char* s) const
    138 {
    139    bool ret = (s != NULL);
    140 
    141     if( ret )
    142     {
    143         int len = strlen(s);
    144         ret = (len < m_length) && equal(m_str, s, len);  // 如果参数字符串 s 长度比当前字符串长度更长,直接返回 false;
    145    }
    146 
    147     return ret;
    148 }
    149 
    150 bool String::startWith(const String& s) const
    151 {
    152     return startWith(s.m_str); // 代码复用了上面的
    153 }
    154 
    155 bool String::endOf(const char* s) const  // s 这个字符串是否是以字符开始
    156 {
    157    bool ret = (s != NULL);
    158 
    159     if( ret )
    160     {
    161         int len = strlen(s);
    162         char* str = m_str + (m_length - len);  // 计算最后 n 个字符表示的字符串;
    163         ret = (len < m_length) && equal(str, s, len);  // 如果参数字符串 s 长度比当前字符串长度更长,直接返回 false;
    164    }
    165 
    166     return ret;
    167 }
    168 
    169 bool String::endOf(const String& s) const
    170 {
    171     return endOf(s.m_str);  // 代码复用了上面的
    172 }
    173 
    174 /* 第 i 个位置插入字符串 s,返回字符串对象是为了实现链式操作 */
    175 String& String::insert(int i, const char* s)
    176 {
    177     if( (0 <= i) && (i <= m_length) )
    178     {
    179         if( (s != NULL) && (s[0] != '') )  // 不为空和空字符串;
    180         {
    181             int len = strlen(s);
    182             char* str = reinterpret_cast<char*>(malloc(m_length + len + 1)); 
    183 
    184             if( str != NULL )
    185             {
    186                 strncpy(str, m_str, i); // 当前字符串的前 i 个字符拷贝出来到 str
    187                 strncpy(str + i, s, len);//将参数字符串s全部拷贝到 str + i 上去
    188                 strncpy(str + i + len, m_str + i, m_length - i); // 将最后字符串拷贝出来
    189                 str[m_length + len] = '';  // 最后添加结束符
    190                 free(m_str);  // 释放当前字符串的堆空间
    191                 m_str = str;  // 使用申请出来的堆空间中的字符串;
    192                 m_length = m_length + len;
    193             }
    194             else
    195             {
    196                 THROW_EXCEPTION(NoEnoughMemoryException, "No memory to insert String value ...");
    197             }
    198         }
    199     }
    200     else
    201     {
    202         THROW_EXCEPTION(IndexOutOfBoundsException, "Parameter i is invalid ...");
    203    }
    204 
    205     return *this;
    206 }
    207 
    208 String& String::insert(int i, const String& s)
    209 {
    210     return insert(i, s.m_str);
    211 }
    212 
    213 String& String::trim()
    214 {
    215     int b = 0;
    216    int e = m_length - 1;
    217 
    218     while( m_str[b] == ' ' ) b++;  // 确定中间字符串开始位置;
    219    while( m_str[e] == ' ' ) e--;  // 确定中间字符窜结束位置;
    220 
    221     if( b == 0 )
    222     {
    223         m_str[e + 1] = '';  // 最开始没有空格的时候;
    224         m_length = e + 1;
    225     }
    226     else
    227     {
    228         for(int i=0, j=b; j<=e; i++, j++)
    229         {
    230             m_str[i] = m_str[j];  // 将当前的含有的非空字符挪到前面去;
    231         }
    232         m_str[e - b + 1] = '';  // 添加结束符
    233         m_length = e - b + 1;  // 合法的字符个数;
    234    }
    235 
    236     return *this;   // 实现链式调用
    237 }
    238 
    239 int String::indexOf(const char* s) const // 子串查找,返回下标
    240 {
    241     return kmp(m_str, s ? s : "");
    242 }
    243 
    244 int String::indexOf(const String &s) const
    245 {
    246     return kmp(m_str, s.m_str);
    247 }
    248 
    249 /* 删除下标 i 处长度为 len 的字符串 */
    250 String& String::remove(int i, int len)   // 和 insert() 返回的是相同的函数,还可以以字符串类继续访问,如查看删除后的字符串等
    251 {
    252     if( (0 <= i ) && (i < m_length) )
    253     {
    254         int n = i;
    255         int m = i + len; // 在 (n, m) 范围之内的字符都要删除掉
    256 
    257         while( (n < m) && (m < m_length) ) // 删除的字符串长度是不能大于当前的长度的,否则没有意义
    258         {
    259             m_str[n++] = m_str[m++];   // 很经典
    260         }
    261 
    262         m_str[n] = '';  //因为n是不断增加的,直到 m 为等于 length
    263         m_length = n; 
    264    }
    265 
    266     return *this;
    267 }
    268 
    269 String& String::remove(const char *s) // 删除子串
    270 {
    271     return remove(indexOf(s), s ? strlen(s) : 0);  
    272 }
    273 
    274 String& String::remove(const String &s) // 删除子串
    275 {
    276     return remove(indexOf(s), s.length());
    277 }
    278 
    279 /* 用 s 替换字符串中的 t */
    280 String& String::replace(const char* t, const char* s)
    281 {
    282    int index = indexOf(t); // 查找 t 的位置
    283 
    284     if( index >= 0 ) // t 存在于当前的字符串中
    285     {
    286         remove(t);  // 不要复制粘贴代码,要复用
    287         insert(index, s);
    288    }
    289 
    290     return *this;
    291 }
    292 
    293 String& String::replace(const String& t, const char* s)
    294 {
    295     return replace(t.m_str, s);
    296 }
    297 
    298 String& String::replace(const char* t, const String& s)
    299 {
    300     return replace(t, s.m_str);
    301 }
    302 
    303 String& String::replace(const String& t, const String& s)
    304 {
    305     return replace(t.m_str, s.m_str);
    306 }
    307 
    308 String String::sub(int i, int len) const  // 查找当前字符串中第 i 个位置长度为 len 的字符串
    310 {
    311    String ret;
    312 
    313     if( (0 <= i) && (i < m_length) )
    314     {
    315         if( len < 0 ) len = 0; // 当小于零时候,不可能,要归一化到 0
    316         if(len+i > m_length) len = m_length - i; // 只能够提取这么长的长度
    317         char* str = reinterpret_cast<char*>(malloc(len + 1));
    318 
    319         if( str != NULL )
    320         {
    321             strncpy(str, m_str + i, len); // 从 m_str + i 位置拷贝 len 长度的字符串,这里 m_str 是字符串起始位置
    322         }
    323 
    324         str[len] = '';
    325         ret = str;  // 返回子串
    326 
    327         free(str);
    328     }
    329     else
    330     {
    331         THROW_EXCEPTION(IndexOutOfBoundsException, "Parameter i is invaid ...");
    332    }
    333 
    334     return ret;
    335 }
    336 
    337 char& String::operator [] (int i)
    338 {
    339     if( (0 <= i) && (i < m_length) )
    340     {
    341         return m_str[i];   // 封装;
    342     }
    343     else
    344     {
    345         THROW_EXCEPTION(IndexOutOfBoundsException, "Parameter i is invalid ...");
    346     }
    347 }
    348 
    349 char String::operator [] (int i) const
    350 {
    351    return (const_cast<String&>(*this))[i]; // 在当前版本当中对非 const 代码复用上面
    352 }
    353 
    354 /* 直接封装 C 语言中的相关函数,直接封装 C 语言库中 strcmp() 函数即可 */
    355 bool String::operator ==(const String& s) const
    356 {
    357     return (strcmp(m_str, s.m_str) == 0);  // strcmp 的函数原型为 int strcmp(const char* s1, const char* s2)
    358 }
    359 
    360 bool String::operator ==(const char* s) const
    361 {
    362     return (strcmp(m_str, s ? s : "") == 0);  // 三目运算符是为了防止 s 为空指针。
    363 }
    364 
    365 bool String::operator != (const String& s) const
    366 {
    367     return !(*this == s);
    368 }
    369 
    370 bool String::operator != (const char* s) const
    371 {
    372     return !(*this == s);
    373 }
    374 
    375 bool String::operator > (const String& s) const
    376 {
    377     return (strcmp(m_str, s.m_str) > 0);
    378 }
    379 
    380 bool String::operator > (const char* s) const
    381 {
    382     return (strcmp(m_str, s ? s : "") > 0);
    383 }
    384 
    385 bool String::operator < (const String& s) const
    386 {
    387     return (strcmp(m_str, s.m_str) < 0);
    388 }
    389 
    390 bool String::operator < (const char* s) const
    391 {
    392     return (strcmp(m_str, s ? s : "") < 0);
    393 }
    394 
    395 bool String::operator >= (const String& s) const
    396 {
    397     return (strcmp(m_str, s.m_str) >= 0);
    398 }
    399 
    400 bool String::operator >= (const char* s) const
    401 {
    402     return (strcmp(m_str, s ? s : "") <= 0);
    403 }
    404 
    405 bool String::operator <= (const String& s) const
    406 {
    407     return (strcmp(m_str, s.m_str) <= 0);
    408 }
    409 
    410 bool String::operator <= (const char* s) const
    411 {
    412     return (strcmp(m_str, s ? s : "") <= 0);
    413 }
    414 
    415 String String::operator + (const String& s) const
    416 {
    417     return (*this + s.m_str);   
    418 }
    419 
    420 String String::operator + (const char* s) const
    421 {
    422     String ret;  // 定义一个两个字符串拼接后结果的字符串对象;
    423     int len = m_length + strlen(s ? s : "");  // 三目运算符是为了防止 s 为空指针;
    424    char* str = reinterpret_cast<char*>(malloc(len + 1));  // 堆空间申请内存,并将 void* 重新解释为 char*
    425 
    426     if( str )
    427     {
    428         strcpy(str, m_str);  // 当前对象的字符串拷贝到申请的堆空间中
    429         strcat(str, s ? s : "");  // 将要添加的字符串拼接到对象字符串后面
    430 
    431         free(ret.m_str);  // 这里归还之前指针所指的内存;
    432 
    433         ret.m_str = str;  // 这里又重新赋值了指针;
    434         ret.m_length = len;
    435     }
    436     else
    437     {
    438         THROW_EXCEPTION(NoEnoughMemoryException, "No memory to add String values");
    439    }
    440 
    441     return ret;
    442 }
    443 
    444 String& String::operator += (const String& s)
    445 {
    446     return (*this = *this + s.m_str); //这里用到了赋值操作符,因此必须实现其重载;
    447 }
    448 
    449 String& String::operator += (const char* s)
    450 {
    451     return (*this = *this + s);
    452 }
    453 
    454 String String::operator - (const String& s) const  // 字符串自身会被改变
    455 {
    456     return String(*this).remove(s);  // 直接调用构造函数产生一个新的临时字符串对象,值和当前字符串对象值相同,然后调用临时对象的remove() 函数将子串删除,最后将删除结果返回,但是当前的字符串没有被改变,因为是拷贝赋值
    457 }
    458 
    459 String String::operator - (const char* s) const  // 字符串自身会被改变
    460 {
    461     return String(*this).remove(s);  // 同上
    462 }
    463 
    464 String& String::operator -= (const String& s) // 字符串自生不会被改变
    465 {
    466     return remove(s);
    467 }
    468 
    469 String& String::operator -= (const char* s)
    470 {
    471     return remove(s);
    472 }
    473 
    474 String& String::operator = (const String& s)
    475 {
    476     return(*this = s.m_str);
    477 }
    478 
    479 String& String::operator = (const char* s)
    480 {
    481     if( m_str != s )
    482     {
    483         char* str = strdup(s ? s : "");  // 复制一份字符串;
    484 
    485         if( str )  // 复制是否成功
    486         {
    487             free(m_str);
    488             m_str = str;
    489             m_length = strlen(m_str);
    490         }
    491         else
    492         {
    493             THROW_EXCEPTION(NoEnoughMemoryException, "No memory to assign new String value...");
    494         }
    495    }
    496 
    497     return *this;
    498 }
    499 
    500 String& String::operator = (char c)
    501 {
    502     char s[] = {c, ''};
    503     return (*this = s);
    504 }
    505 
    506 String::~String()
    507 {
    508     free(m_str);
    509 }
    510 
    511 }

    10,本节课字符串类测试代码:

     1 #include <iostream>
     2 #include "DTString.h"
     3 
     4 using namespace std;
     5 using namespace DTLib;
     6 
     7 void test_1()
     8 {
     9     cout << "test_1() begin ..." << endl;
    10     String s;
    11    s = 'D';
    12 
    13     cout << s.str() << endl;
    14     cout << s.length() << endl;
    15     cout << (s == "D") << endl;
    16    cout << (s > "CCC") << endl;
    17 
    18    s += " Delphi Tang ";
    19 
    20     cout << s.str() << endl;
    21     cout << s.length() << endl;
    22     cout << (s == "D Delphi Tang ") << endl;
    23     cout << "test_1() end ..." << endl;
    24 }
    25 
    26 void test_2()
    27 {
    28    cout << "test_2() begin ..." << endl;
    29 
    30     String a[] = {"E", "D", "C", "B", "A"};  // 字符串的比较遵循字典当中的顺序。
    31    String min = a[0];
    32 
    33     for(int i=0; i<5; i++)
    34     {
    35         if( min > a[i] )
    36         {
    37             min = a[i];
    38         }
    39 }
    40 
    41    cout << "min = " << min.str() << endl;
    42 
    43     cout << "test_2() end ..." << endl;
    44 }
    45 
    46 int main()
    47 {
    48     test_1();
    49    test_2();
    50 
    51     return 0;
    52 }

    11,字符串类实现的实质是:

           1,使用面向对象的技术来对原来所使用过的 C 语言字符串相关函数进行合理封装,方便开发;

           2,封装达到的最终目的是代码复用;

          

    12,小结:

           1,C/C++ 语言本身不支持字符串类型;

           2,C 语言通过字符数组和一组函数支持字符串操作;

                  1,不方便也不利于代码复用

           3,C++ 通过自定义字符串类型支持字符串操作;

                  1,通过面向对象的技术来封装 C 语言中的函数,封装后的结果是我们拥有一个完整的字符串类型,并且这个字符串类型在实际工程开发中非常方便;

           4,字符串类型通过 C 语言中的字符串函数实现;

  • 相关阅读:
    测试用例设计--边界值
    测试用例设计--等价类划分
    实战JAVA虚拟机 JVM故障诊断与性能优化(八)
    Centos-Mysql远程访问
    实战JAVA虚拟机 JVM故障诊断与性能优化(七)
    实战JAVA虚拟机 JVM故障诊断与性能优化(六)--->JConsole And Visual VM
    实战JAVA虚拟机 JVM故障诊断与性能优化(六)
    jdk 1.8 VisualVM 插件 地址 变更
    实战JAVA虚拟机 JVM故障诊断与性能优化(七)--->无处不在的字符串:String在虚拟机中的实现
    本地git项目,push到github上
  • 原文地址:https://www.cnblogs.com/dishengAndziyu/p/10923271.html
Copyright © 2011-2022 走看看