zoukankan      html  css  js  c++  java
  • STL string 模拟

    下面的代码来自c++ primer plus第5版第12章,书中代码写的非常好:

    // string1.h -- fixed and augmented string class definition
    #include <iostream>
    using std::ostream;
    using std::istream;
    
    #ifndef STRING1_H_
    #define STRING1_H_
    class String
    {
    private:
        char * str;             // pointer to string
        int len;                // length of string
        static int num_strings; // number of objects
        static const int CINLIM = 80;  // cin input limit
    public:
    // constructors and other methods
        String(const char * s); // constructor
        String();               // default constructor
        String(const String &); // copy constructor
        ~String();              // destructor
        int length () const { return len; }
    // overloaded operator methods    
        String & operator=(const String &);
        String & operator=(const char *);
        char & operator[](int i);
        const char & operator[](int i) const; 
    // overloaded operator friends
        friend bool operator<(const String &st, const String &st2);
        friend bool operator>(const String &st1, const String &st2);
        friend bool operator==(const String &st, const String &st2);
        friend ostream & operator<<(ostream & os, const String & st);
        friend istream & operator>>(istream & is, String & st);
    // static function
        static int HowMany();
    };
    #endif
    num_strings 主要是为了统计对象创建的个数.
    cpp文件:
    // string1.cpp -- String class methods
    #include <cstring>                 // string.h for some
    #include "string1.h"               // includes <iostream>
    using std::cin;
    using std::cout;
    
    // initializing static class member
    
    int String::num_strings = 0;
    
    // static method
    int String::HowMany()
    {
        return num_strings;
    }
    
    // class methods
    String::String(const char * s)     // construct String from C string
    {
        len = std::strlen(s);          // set size
        str = new char[len + 1];       // allot storage
        std::strcpy(str, s);           // initialize pointer
        num_strings++;                 // set object count
    }
    
    String::String()                   // default constructor
    {
        len = 4;
        str = new char[1];
        str[0] = '';                 // default string
        num_strings++;
    }
    
    String::String(const String & st)
    {
        num_strings++;             // handle static member update
        len = st.len;              // same length
        str = new char [len + 1];  // allot space
        std::strcpy(str, st.str);  // copy string to new location
    }
    
    String::~String()                     // necessary destructor
    {
        --num_strings;                    // required
        delete [] str;                    // required
    }
    
    // overloaded operator methods    
    
        // assign a String to a String
    String & String::operator=(const String & st)
    {
        if (this == &st)
            return *this;
        delete [] str;
        len = st.len;
        str = new char[len + 1];
        std::strcpy(str, st.str);
        return *this;
    }
    
        // assign a C string to a String
    String & String::operator=(const char * s)
    {
        delete [] str;
        len = std::strlen(s);
        str = new char[len + 1];
        std::strcpy(str, s);
        return *this;
    }
    
        // read-write char access for non-const String
    char & String::operator[](int i)
    {
        return str[i];
    }
    
        // read-only char access for const String
    const char & String::operator[](int i) const
    {
        return str[i];
    }
    
    // overloaded operator friends
    
    bool operator<(const String &st1, const String &st2)
    {
        return (std::strcmp(st1.str, st2.str) < 0);
    }
    
    bool operator>(const String &st1, const String &st2)
    {
        return st2.str < st1.str;
    }
    
    bool operator==(const String &st1, const String &st2)
    {
        return (std::strcmp(st1.str, st2.str) == 0);
    }
    
        // simple String output
    ostream & operator<<(ostream & os, const String & st)
    {
        os << st.str;
        return os; 
    }
    
        // quick and dirty String input
    istream & operator>>(istream & is, String & st)
    {
        char temp[String::CINLIM];
        is.get(temp, String::CINLIM);
        if (is)
            st = temp;
        while (is && is.get() != '
    ') //  丢弃多余的字符
            continue;
        return is; 
    }

    代码有许多值得注意的地方:

    1.为什么构造函数里面是

    str = new char[1];
    str[0] = '';
    而不是
    str=new char;
    上面2中方式分配的内存量相同,区别在于前者与析构函数兼容,而后者不兼容。析构函数含有如下代码:
    delete[] str;
    delete[] 与使用new【】初始化的指针和空指针都兼容,因此对于下面的代码:
    str = new char[1];
    str[0] = '';
    可修改为
    str=0;//set str to the null pointer

    对于以其他方式初始化的指针,使用delete[] 删除,结果是不确定的:

    char words[15]="ab";

    char *p=words;

    char *p2=new char;

    char *p3;

    delete[] p1; //undefined,so don't do it //会产生run time error

    delete[] p2;//undefined,so don't do it

    delete[] p3;//undefined,so don't do it 会产生run time error.

    上面几种方式都不正确。

    2.为什么我们要2次重载:

    // read-write char access for non-const String
    char & String::operator[](int i)
    {
    return str[i];
    }

    // read-only char access for const String
    const char & String::operator[](int i) const
    {
    return str[i];
    }

    是因为如果没有重载常量的[],下面的代码将出错:

    const String s("hello");

    cout<<a[1];

    元素是s是常量,而上述方法无法确保不修改数据。

    所以在重载时,c++将区分常量和非常量函数的特征标

    有了上述的重载后,

    const string s("helloo");

    cin>>s[1];就会报错。

    istream的get函数有许多重载版本:

    single character (1)
      int get();
      istream& get (char& c);
    c-string (2)
      istream& get (char* s, streamsize n);
      istream& get (char* s, streamsize n, char delim);
    stream buffer (3)
      istream& get (streambuf& sb);
      istream& get (streambuf& sb, char delim);

    cin.get()读取单个字符并返回,http://www.cplusplus.com/reference/istream/istream/get/

    可不可以将构造函数换成:

    String()

    {

     str="default string";

     len=strlen(str);

    }

    答:不可以,没有使用new[]来初始化str,对默认对象调用析构函数时,使用delete【】来释放,对不是使用new初始化的指针使用

    delete,其结果将是不确定的,并可能是有害的。

    在构造函数中使用new应注意的问题

    使用new来初始化对象的指针成员时必须要特别小心,具体地说,应该是这样:

    1.如果在构造函数中使用new来初始化成员指针,则应在析构中调用delete

    2,new和delete必须相互兼容,new对于delete,new[]对于delete[]。

    3.如果有多个构造函数,则必须以相同的方式使用new,要么带中括号,要么都不带。因为只有一个析构函数,因此所有的构造函数都必须与他兼容。不过,可以在一个构造函数中使用new来初始化指针,而在另一个构造函数中将指针初始化为空(null或0,这是

    因为delete(无论是带【】还是不带【】)都可以用于空指针

    ostream & operator<<(ostream & os, const String & st) 
    可以可以不返回引用?
    答:绝对不可以
    cout一般都可以链式操作cout<<s<<s2;
    如果不返回引用,如果返回类型为ostream,将要求ostream类的复制构造函数,而ostream没有任何公有的复制构造函数。幸运的是,
    返回一个指向cout的引用不会带来任何问题。
    如果不写成引用,编译不通过。报错:
    无法访问 private 成员(在“std::basic_ios<_Elem,_Traits>”类中声明)
    我们在xiobase文件中科院看到:
    private:
    ios_base& __CLR_OR_THIS_CALL operator=(const ios_base& _Right)
     private: ios_base(const ios_base&);
    显然,拷贝构造函数与复制操作符都声明为私有。 因此,重载操作符应该如下: ostream& operator<<(ostream &out , CA &ca)

    istream也是如此。

    测试:

    这是书本的测试:

    // sayings1.cpp -- using expanded String class
    // compile with string1.cpp
    #include <iostream>
    #include "string1.h" 
    const int ArSize = 10;
    const int MaxLen =81;
    int main()
    {
        using std::cout;
        using std::cin;
        using std::endl;
        String name;
        cout <<"Hi, what's your name?
    >> ";
        cin >> name;
    
        cout << name << ", please enter up to " << ArSize
             << " short sayings <empty line to quit>:
    ";
        String sayings[ArSize];     // array of objects
        char temp[MaxLen];          // temporary string storage
        int i;
        for (i = 0; i < ArSize; i++)
        {
            cout << i+1 << ": ";
            cin.get(temp, MaxLen);
            while (cin && cin.get() != '
    ')
                continue;
            if (!cin || temp[0] == '')    // empty line?
                break;              // i not incremented
            else
                sayings[i] = temp;  // overloaded assignment
        }
        int total = i;              // total # of lines read
    
        cout << "Here are your sayings:
    ";
        for (i = 0; i < total; i++)
            cout << sayings[i][0] << ": " << sayings[i] << endl;
    
        int shortest = 0;
        int first = 0;
        for (i = 1; i < total; i++)
        {
            if (sayings[i].length() < sayings[shortest].length())
                shortest = i;
            if (sayings[i] < sayings[first])
                first = i;
        }
        cout << "Shortest saying:
    " << sayings[shortest] << endl;;
        cout << "First alphabetically:
    " << sayings[first] << endl;
        cout << "This program used "<< String::HowMany() 
             << " String objects. Bye.
    ";
    
        return 0; 
    }
    View Code

    这是我的测试;

    #include"String.h"
    #include<cassert>
    #include<string>
    
    
    int main()
    {
     
        
        //copy constrtor 
        String s1("abc");
        cout<<s1<<endl;
    
        String s2(s1);
        cout<<s2<<endl;
    
        // operator=(const char* s);
        s1="helloworld";
        cout<<s1<<endl;
        // operator=(const String & other);
        String s3("youcan");
        s1=s3;
        cout<<s1<<endl;
        
        //调用赋值构造函数
        String s4="dddd";
        cout<<s4<<endl;
        cout<<s1.howMany()<<endl;//输出4
    
        String s5="helloworld";
        cout<<s5[0]<<endl;
        s5[0]='z';
        cout<<s5<<endl;
        const String s6("const");
        cout<<s6[0]<<endl;
     
    }

    上面的全都来自c++ primer plus这本书。

  • 相关阅读:
    Maven3路程(一)用Maven创建第一个web项目(1)
    ECLIPSE下SVN的创建分支/合并/切换使用
    Oracle 客户端免安装数据库连接
    如何用Maven创建web项目(具体步骤)
    使用Eclipse构建Maven项目 (step-by-step)
    Maven安装配置
    动画基础(隐式动画)
    CA*Layer(CAReplicatorLayer--)
    CA*Layer(CATransformLayer--CAGradientLayer)
    CA*Layer(CAShapeLayer--CATextLayer)
  • 原文地址:https://www.cnblogs.com/youxin/p/3280270.html
Copyright © 2011-2022 走看看