C++ - string 基本版

真正去了解如何写一个string类的时候,发现有好多知识点。

  • 复制控制(复制构造函数、赋值操作符、析构函数)
  • 运算符重载(+, ==, !=, <, <=, >, >=, +=, []等等)
  • 深拷贝(对于字符串拷贝的处理)
  • 友元(cin, cout)
  • 内联函数(为了提高效率,这些函数都是内联函数)
  • const的用法(返回值为常量、常量函数、输入为常量)
  • 引用(输入为引用、返回值为引用(如+, []))
  • 异常安全(operator=)

这些也还只是基本版的内容,还有

  • 隐式共享写时拷贝(智能指针)
  • C++11的右值引用、Move语义
  • iterator
  • gcc中string(basic_string)的写法又是另外一种层面的东西了……

本文给出基本版的代码

#include <iostream>
#include <vector>
#include <string>
#include <iomanip> // setw
#include <cstdio>
using namespace std;

class MyString { // inline
public:
    // constructor
    MyString(const char* str = NULL);
    MyString(const MyString&);
    MyString(size_t, char); // ? memset?
    // destructor
    ~MyString();

    bool empty();
    size_t size() const; // string::size_type?

    const char* c_str() const;
    void swap(MyString&);
    // operator +, ==, !=, <, <=, >, >=, +=
    char& operator[](size_t); // unsigned int??
    MyString& operator=(const MyString&);
    MyString operator+(const MyString&) const;
    bool operator==(const MyString&);
    // friend istream, ostream
    friend istream& operator>>(istream&, MyString&);
    friend ostream& operator<<(ostream&, MyString&);
private:
    char *m_data;

};

int main() {
    MyString mstr, s1, s2;
    cin >> mstr;
    cout << mstr << endl;
    mstr[0] = 'k';
    cout << mstr << endl;
    s1 = s2 = mstr;
    s2[2] = '3';
    cout << s1 << " " << (s1 == s2) << " " << s2 << endl;
    MyString s3(10, 'm');
    cout << s3 << endl;
    return 0;
}
inline MyString::MyString(const char* str) {
    // error C2572: “MyString::MyString”: 重定义默认参数 : 参数 1  // 去掉 = NULL
    if (!str) {
        m_data = new char[1];
        m_data[0] = '\0';
    }
    else {
        m_data = new char[strlen(str) + 1];
        strcpy(m_data, str);
    }
}
inline MyString::MyString(const MyString &object) {
    m_data = new char[object.size() + 1];
    strcpy(m_data, object.c_str());
}
inline MyString::MyString(size_t n, char ch) {
    m_data = new char[n + 1];
    memset(m_data, ch, n);
    m_data[n] = '\0';
}
inline MyString::~MyString() {
    delete []m_data;
}
size_t MyString::size() const {
    return strlen(m_data);
}
const char* MyString::c_str() const {
    return m_data;
}

void MyString::swap(MyString &rhs) {
    std::swap(m_data, rhs.m_data);
}

char& MyString::operator[](size_t i) {
    // 考虑错误处理
    return m_data[i];
}
MyString& MyString::operator=(const MyString& rhs) {
    if (this != &rhs) {
        MyString temp(rhs);
        swap(temp);
    }
    return *this;
}
bool MyString::operator==(const MyString& rhs) {
    return strcmp(m_data, rhs.c_str()) ? false : true;
}
MyString MyString::operator+(const MyString& rhs) const {
    MyString newS;
    //if (!rhs.m_data) { // 不可能为NULL
    //  newS = *this;
    //}
    //else if (!this->m_data) {
    //  newS = rhs.m_data;
    //}
    //else {
        newS.m_data = new char[size() + rhs.size() + 1];
        strcpy(newS.m_data, m_data);
        strcat(newS.m_data, rhs.m_data);
    //}
    return newS;
}

istream& operator>>(istream& in, MyString& rhs) {
    // 第一种方法:字符串长度受限
    //char temp[255];
    //in >> setw(255) >> temp;
    ////rhs = MyString(temp); // ok
    //rhs = temp;
    ////strcpy(rhs.m_data, temp); // ??有问题,确实有问题,m_data并没有分配空间,因此也可以先分配空间再拷贝
    //return in;

    // 第二种方法:字符串长度不受限,但在个别情况下有bug,详见注释
    //const int BUFFER_SIZE = 255; // 可以以5来做测试
    //char buffer[BUFFER_SIZE];
    //char *end = buffer + BUFFER_SIZE - 1;
    //rhs = ""; // clear
    //do {
    //  *end = '#';
    //  //in >> setw(BUFFER_SIZE) >> buffer; // 如果输入恰好是BUFFER_SIZE - 1,则会出问题
    //  //in.get(buffer, BUFFER_SIZE); // 并不能以空格分隔,直接输入换行也会出问题,暂时还不清楚为什么?难道是因为get了两次?
    //  in.get(buffer, BUFFER_SIZE, ' '); // 如果以空格分隔,又不能识别换行
    //  rhs += buffer;
    //} while (*end == '\0');
    //in.get();
    //// http://www.cplusplus.com/reference/istream/istream/get/
    //// The delimiting character is not extracted from the input sequence if found, 
    //// and remains there as the next character to be extracted from the stream (see 
    //// getline for an alternative that does discard the delimiting character).
    //return in;

    // 第三种方法:单字符处理,尝试get(char &c)
    const int BUFFER_SIZE = 255; // 可以以5来做测试
    char buffer[BUFFER_SIZE];
    int i = 0;
    char ch;
    rhs = "";
    // 标准输入流忽略空格和\n // http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/
    do {
        in.get(ch);
    } while (ch == ' ' || ch == '\n');

    while (true) {
        if (ch == ' ' || ch == '\n') {
            buffer[i] = '\0';
            rhs += buffer;
            break;
        }
        else {
            buffer[i++] = ch;
            if (i == BUFFER_SIZE - 1) {
                buffer[i] = '\0';
                rhs += buffer;
                i = 0;
            }
        }
        in.get(ch);
    }
    return in;
}
ostream& operator<<(ostream& out, MyString& rhs) {
    out << rhs.m_data;
    return out;
}

最后附上一些参考资料。
STL 的string类怎么啦?
意图(Intention)、规格(Specification)、实现(Implementation)
标准C++类string的Copy-On-Write技术(一)
引用计数器(智能指针)
C++面试中string类的一种正确写法
C++ string实现原理
C++ string类的隐式共享写时拷贝的实现及设计要点
C++中String类的实现

你可能感兴趣的:(C++,String,实现)