• 了解string以及简单模拟实现(c++)


    00. 前言

    我们竟然要用string,就要知道string里面有什么?
    模拟的意义在于了解它的底层逻辑更便于我们去使用。
    参考文档:
    链接:string类

    01. string中常用类成员

    namespace Ding
    {
        class string
        {
        public:
            typedef char* iterator;
            typedef const char* const_iterator;
            // iterator 
            const_iterator begin() const;
            const_iterator end() const;
            iterator begin();
            iterator end();
    
    
            string(const char* str = "")
            {
                _size = strlen(str);
                _capacity = _size;
                _str = new char[_capacity + 1];
    
                strcpy(_str, str);
            }
    
            /* 传统写法
            string(const string& s)
              :_str(new char[s._capacity+1]);
              ,_size(s._size);
              ,_capacity(s._capacity);
            {
              strcpy(_str, s._str);
            }
    
              */
            void swap(string& tmp)
            {
                ::swap(_str, tmp._str);
                ::swap(_size, tmp._size);
                ::swap(_capacity, tmp._capacity);
            }
    
            string(const string& s)
                :_str(nullptr)
                , _size(0)
                , _capacity(0)
            {
                string tmp(s._str);
                swap(tmp);
            }
    
    
            ~string()
            {
                delete[] _str;
                _str = nullptr;
                _capacity = _size = 0;
            }
            //string& operator=(const string &s);
            string& operator=(string s);
            string& operator=(char c);
    
            //access
            char& operator[](size_t pos);
            const char& operator[](size_t pos) const;
    
            //modify
            void push_back(char c);
    
            string& operator+=(char c);
            string& operator+=(const string& str);
    
            void append(const char* str);
    
            string& operator+=(const char* str);
    
            void clear();
    
            const char* c_str() const;
    
            void reserve(size_t n);
    
            //capacity
            size_t size() const;
    
            size_t capacity() const;
    
            bool empty() const;
            void resize(size_t n, char c = '\0');
    
            // 在pos位置上插入字符c/字符串str,并返回该字符的位置
            string& insert(size_t pos, char c);
            string& insert(size_t pos, const char* str);
    
            // 删除pos位置上的元素
            string& erase(size_t pos, size_t len = npos);
            //
            bool operator<(const string& s);
    
            bool operator<=(const string& s);
    
            bool operator>(const string& s);
    
            bool operator>=(const string& s);
    
            bool operator==(const string& s);
    
            bool operator!=(const string& s);
    
            // 返回c在string中第一次出现的位置
    
            size_t find(char c, size_t pos = 0) const;
    
            // 返回子串s在string中第一次出现的位置     
    
            size_t find(const char* s, size_t pos = 0) const;
    
            //返回子字符串
            string substr(size_t pos, size_t len) const;
        private:
            char* _str;
            size_t _size;
            size_t _capacity;
        public:
            const static size_t npos=-1; //此处叫声明--给缺省值
        };
    
    //不使用友元的原因是未访问私有成员变量。
        ostream& operator<<(ostream& out, const string& s);
        istream& operator>>(istream& in, string& s);
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131

    解释:
    我们为了与库里的string区分开,我们使用命名空间加以区别。

    03. 为什么学习string

    1. C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。
    .
    2. 在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本都使用string类,很少有人去使用C库中的字符串操作函数。

    04. string模拟实现

    0. 析构函数

     ~string()
     {
       delete[] _str;
       _str = nullptr;
       _capacity = _size = 0;
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    1. string类对象的常见构造

    • 函数名称:
      • string()
      • string(const char* s)
      • string(const string&s)
    • 功能说明
      • 构造空的string类对象,即空字符串。
      • 用C-string来构造string类对象
      • 拷贝构造函数

    0)测试案例:

    void Teststring1()
    {
    	string s1; // 构造空的string类对象s1
    	string s2("hello Ding"); // 用C格式字符串构造string类对象s2
    	string s3(s2); // 拷贝构造s3
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    1)string() --构造函数

    string()
    	:_str(new char[1])
    	, _size(0)  //记录有效值
    	, _capacity(0) //字符串最后的‘\0’不算有效值
    	//上面的是初始化列表的应用。
    {
    	_str[0] = '\0';
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    空字符串中含"\0"

    2)string(const char* s)–带参构造

    string(const char* str)
    {
        _size = strlen(str);
        _capacity = _size;
        _str = new char[_capacity + 1];
    
        strcpy(_str, str);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    1-2)string(const char* str = “”)–缺省构造

    存在1)2)这两种构造方式,这时我们就可以俩者结合一下;利用缺省的性质来构造

    string(const char* str = "") //”“空字符串隐含一个'\0'
    {
    	_size = strlen(str);
    	_capacity = _size;
    	_str = new char[_capacity + 1];
    
    	strcpy(_str, str);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    深浅拷贝的问题

    若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。
    先看下面一段代码:

    typedef int DataType;
    class Stack
    {
    public:
    	Stack(size_t capacity = 10)
    	{
    		_array = (DataType*)malloc(capacity * sizeof(DataType));
    		if (nullptr == _array)
    		{
    			perror("malloc申请空间失败");
    			return;
    		}
    		_size = 0;
    		_capacity = capacity;
    	}
    	void Push(const DataType& data)
    	{
    		// CheckCapacity();
    		_array[_size] = data;
    		_size++;
    	}
    	~Stack()
    	{
    		if (_array)
    		{
    			free(_array);
    			_array = nullptr;
    			_capacity = 0;
    			_size = 0;
    		}
    	}
    private:
    	DataType* _array; 
    	size_t _size;
    	size_t _capacity;
    };
    int main()
    {
    	Stack s1;
    	s1.Push(1);
    	s1.Push(2);
    	s1.Push(3);
    	s1.Push(4);
    	Stack s2(s1);
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    一运行上面代码就会崩溃。
    在这里插入图片描述

    编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝,会导致堆上开辟的空间,二次释放(free)
    
    • 1

    示意图:
    在这里插入图片描述

    如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。

    3)string(const string&s)–拷贝构造函数

    切记拷贝构造的时候存在深浅拷贝问题;我们需要另开空间,来解决。

    • 传统写法
    //传统写法
    string(const string& s)
    	:_str(new char[s._capacity + 1]);//初始化列表
    , _size(s._size);
    , _capacity(s._capacity);
    {
    	strcpy(_str, s._str);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 现代写法(推荐使用)
    void swap(string& tmp)
    {
        ::swap(_str, tmp._str);//::去全局去找,也就是调用库里面的swap
        ::swap(_size, tmp._size);
        ::swap(_capacity, tmp._capacity);
    }
    
    string(const string& s)
        :_str(nullptr)
        , _size(0)
        , _capacity(0)
        //初始化列表
    {
        string tmp(s._str);//调用构造函数。
        swap(tmp);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    测试结果

    在这里插入图片描述

    2. string类对象的容量操作

    • 函数名称
      • size与length(我们通常使用size)
      • capacity
      • empty
      • clear
      • reserve
      • resize
    • 功能说明
      • 返回字符串有效字符长度
      • 返回空间总大小
      • 检测字符串释放为空串,是返回true,否则返回false
      • 清空有效字符
      • 为字符串预留空间
      • 将有效字符的个数该成n个,多出的空间用字符c填充

    0)代码演示

    在这里插入图片描述
    当然写了属于自己的流输出cout也可以测。

    在这里插入图片描述
    测试代码:

    void Teststring2()
    {
    	// 注意:string类对象支持直接用cin和cout进行输入和输出
    	Ding::string s("hello, bit!!!");//调用库里面的。
    	cout << s.size() << endl;
    	cout << s.capacity() << endl;
    	cout << s << endl;
    
    	// 将s中的字符串清空,注意清空时只是将size清0,不改变底层空间的大小
    	s.clear();
    	cout << s.size() << endl;
    	cout << s.capacity() << endl;
    
    	// 将s中有效字符个数增加到10个,多出位置用'a'进行填充
    	// “aaaaaaaaaa”
    	s.resize(10, 'a');
    	cout << s.size() << endl;
    	cout << s.capacity() << endl;
    
    	// 将s中有效字符个数增加到15个,多出位置用缺省值'\0'进行填充
    	// "aaaaaaaaaa\0\0\0\0\0"
    	// 注意此时s中有效字符个数已经增加到15个
    	s.resize(15);
    	cout << s.size() << endl;
    	cout << s.capacity() << endl;
    	cout << s << endl;
    
    	// 将s中有效字符个数缩小到5个
    	s.resize(5);
    	cout << s.size() << endl;
    	cout << s.capacity() << endl;
    	cout << s << endl;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    1)size–字符串有效字符长度

    我的是定义与声明分离,所以需要Ding::string:: 域。

    size_t Ding::string::size() const
    {
        return _size;
    }
    
    • 1
    • 2
    • 3
    • 4

    2)capacity–开辟空间总大小

    size_t Ding::string::capacity() const
    {
        return _capacity;
    }
    
    • 1
    • 2
    • 3
    • 4

    3)empty–检测字符串是否为空

    bool Ding::string::empty() const
    {
        return _capacity == 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4)clear–清空有效字符

    清楚字符串,我们保证有效值为零,理论是是空字符串就可以了。

    void Ding::string::clear()
    {
        _str[0] = '\0';
        _size = 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5)reserve–字符串预留空间

    void Ding::string::reserve(size_t n)
    {
        if (n > _capacity)//检验是否扩容
        {
            char* tmp = new char[n + 1];
            strcpy(tmp, _str);
            delete[] _str;
    
            _str = tmp;
            _capacity = n;
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    6)resize–将有效字符的个数该成n个,多出的空间用字符c填充

    void Ding::string::resize(size_t n, char c)
    {
        reserve(n); //空间不够时开空间
    
        if (n > _size)
        {
            //插入
            for (size_t i = _size; i < n; i++)
            {
                _str[i] = c;
            }
            _str[n] = '\0';
            _size = n;
        }
        else
        {
            _str[n] = '\0';
            _size = n;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3. string类对象的访问及遍历操作

    • 函数名称
      • operator[]
      • begin+ end begin
    • 功能说明
      • 返回pos位置的字符,const string类对象调用
      • 范围for
      • 获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器
      • C++11支持更简洁的范围for的新遍历方式

    0)代码演示

    void Teststring3()
    {
    	std::string s("Hello Ding");
    	// 3种遍历方式:
    	// 需要注意的以下三种方式除了遍历string对象,还可以遍历是修改string中的字符,
    	// 另外以下三种方式对于string而言,第一种使用最多
    	// 1. for+operator[]
    	for (size_t i = 0; i < s.size(); ++i)
    		cout << s[i] << "-";
    	cout << endl;
    
    	// 2.迭代器
    	// C++11之后,直接使用auto定义迭代器,让编译器推到迭代器的类型
    	// 
    	//std::string::iterator it = s.begin();
    	auto it = s.begin();
    	while (it != s.end())
    	{
    		cout << *it << "-";
    		++it;
    	}
    	cout << endl;
    
    	
    	// 3.范围for
    	for (auto ch : s)
    		cout << ch << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    在这里插入图片描述
    说明:
    范围for的底层逻辑就是迭代器。
    迭代器可能是指针也可能不是指针,但它像指针那样用。
    typedef char iterator;*
    typedef const char const_iterator;*

    2)迭代器iterator

    const_iterator begin() const;
    const_iterator end() const;
    iterator begin();
    iterator end();
    
    • 1
    • 2
    • 3
    • 4

    模拟实现:

    Ding::string::iterator Ding::string::begin()
    {
        return _str;
    }
    Ding::string::iterator Ding::string::end()
    {
        return _str + _size;
    }
    
    Ding::string::const_iterator Ding::string::begin() const
    {
        return _str;
    }
    
    Ding::string::const_iterator Ding::string::end() const
    {
        return _str + _size;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    3)operator[]

    char& Ding::string::operator[](size_t pos)
    {
        assert(pos < _size);
    
        return _str[pos];
    }
    
    const char& Ding::string::operator[](size_t pos) const
    {
        assert(pos < _size);
    
        return _str[pos];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4. string类对象的修改操作

    • 函数名称
      • push_back
      • append
      • operator+=
      • c_str
      • find + npos
      • substr
    • 功能说明
      • 在字符串后尾插字符c
      • 在字符串后追加一个字符串
      • 在字符串后追加字符串str或字符
      • 返回C格式字符串
      • 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置 (npos我们模拟定义是无符号-1)
      • 在str中从pos位置开始,截取n个字符,然后将其返回(子字符串)

    注意:

    1. 在string尾部追加字符时,s.push_back© / s.append(1, c) / s += 'c’三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。
    2. 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。

    代码演示:

    void Teststring4()
    {
    	Ding::string str;
    	str.push_back(' ');   // 在str后插入空格
    	str.append("Hello");  // 在str后追加一个字符"hello"
    	str += 'D';           // 在str后追加一个字符'b'   
    	str += "ing";          // 在str后追加一个字符串"it"
    	cout << str << endl;
    	cout << str.c_str() << endl;   // 以C语言的方式打印字符串
    
    
    	// npos是string里面的一个静态成员变量
    	// static const size_t npos = -1;
    
    	// 取出url中的域名
    	Ding::string url("http://www.cplusplus.com/reference/string/string/find/");
    	cout << url << endl;
    	size_t start = url.find("://");
    	if (start == Ding::string::npos)
    	{
    		cout << "invalid url" << endl;
    		return;
    	}
    	start += 3;
    	size_t finish = url.find('/', start);
    	Ding::string address = url.substr(start, finish - start);
    	cout << address << endl;
    
    	// 删除url的协议前缀
    	size_t pos = url.find("://");
    	url.erase(0, pos + 3);
    	cout << url << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    在这里插入图片描述

    1)string—insert模拟实现

    Ding::string& Ding::string::insert(size_t pos, char c)
    {
        assert(pos <= _size);
        //扩容 
        if (_size == _capacity)
        {
            size_t capacity = _capacity == 0 ? 4 : 2 * _capacity;
    
            reserve(capacity);
        }
    //挪动数据
        size_t end = _size + 1;
        while (end > pos)
        {
            _str[end] = _str[end - 1];
            --end;
        }
    
        _str[pos] = c;
        ++_size;
    
        return *this;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    Ding::string& Ding::string::insert(size_t pos, const char* str)
    {
        assert(pos <= _size);
        size_t len = strlen(str);
        //扩容
        if (_size + len > _capacity)
        {
            reserve(_size + len);
        }
    
        size_t end = _size + len;
        while (end > pos)
        {
            _str[end] = _str[end - 1];
            --end;
        }
        strcpy(_str + pos, str);
        _size += len;
    
        return *this;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    2)string—push_back模拟实现

    尾插:

    void Ding::string::push_back(char c)
    {
        /*if(_size==_capacity)//扩容
        {
          size_t capacity= _capacity==0? 4 : 2*_capacity;
    
          reserve(capacity);
        }
        _str[_size]=c;
        ++_size;
        _str[_size]='\0';
      */
    
        insert(_size, c);//调用
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3)string–append模拟实现

    void Ding::string::append(const char* str)
    {
        /* size_t len = strlen(str);
    
         if(_size + len > _capacity)
         {
           reserve(_size + len);//扩容
         }
    
         strcpy(_str+_size, str);
         _size = _size + len;
         _str[_size] = '\0';
       */
    
        insert(_size, str);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    4)string–find模拟实现

    // 返回子串s在string中第一次出现的位置     
    
    size_t Ding::string::find(const char* s, size_t pos) const
    {
        assert(pos < _size);
        assert(s);
    
        const char* str = strstr(_str + pos, s);//c语言查子字符串
        if (str == nullptr)
        {
            return npos;
        }
        else
        {
            return str - _str;//指针相减,得到两者之间距离。
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    单个字符

    size_t Ding::string::find(char c, size_t pos) const
    {
        assert(pos < _size);
    
        for (size_t i = pos; i < _size; ++i)
        {
            if (_str[i] == c)
            {
                return i;
            }
    
        }
    
        return npos;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    5)string–erase模拟实现

    Ding::string& Ding::string::erase(size_t pos, size_t len)
    {
        assert(pos < _size);
    
        if (len == npos || len + pos >= _size)//删完
        {
            _str[pos] = '\0';
            _size = pos;
        }
        else//pos位置以后的删完
        {
            strcpy(_str + pos, _str + pos + len);
            _size -= len;
        }
    
        return *this;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    6)string–+= 模拟实现

    Ding::string& Ding::string::operator+=(char c)
    {
        push_back(c);
        return *this;
    }
    
    Ding::string& Ding::string::operator+=(const string& str)
    {
        append(str._str);
        return *this;
    }
    
    Ding::string& Ding::string::operator+=(const char* str)
    {
        append(str);
        return *this;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    string–赋值重载

    注意:深浅拷贝问题。

    Ding::string& Ding::string::operator=(string& s)
    {
    	if(this != &s)//排除自己给自己赋值
    	{
    		string tmp(s._str);//构造
    		swap(tmp);
    	}
    
        return *this;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    下面使用传值,那么下面s就是临时拷贝,相等与替代了tmp的作用;此时也是深拷贝。

    Ding::string& Ding::string::operator=(string s)
    {
        swap(s);
        return *this;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    单个字符。

    Ding::string& Ding::string::operator=(char c)
    { 
    	(*this).clear;//先清除。
        *this += c;
    
        return *this;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    7)string—substr模拟实现

    // 返回字字符串
    Ding::string Ding::string::substr(size_t pos, size_t len) const
    {
        assert(pos < _size);
    
        size_t reallen = len;
        if (len == npos || pos + len > _size)//返回整个字符串
        {
            reallen = _size - pos;
        }
    
        string sub;
        for (size_t i = pos; i < reallen + pos; ++i)
        {
            sub += _str[i];
        }
    
        return sub;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    8)string–c_str模拟实现

    const char* Ding::string::c_str() const
    {
        return _str;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5. string类非成员函数

    • 函数 :
      • operator>>
      • operator<<
    • 功能说明:
      • 输入运算符重载
      • 输出运算符重载

    1)流插入-cout

    思路:一个一个字符的读取

    ostream& Ding::operator<<(ostream& out, const string& s)
    {
        for (size_t i = 0; i < s.size(); ++i)
        {
            out << s[i];
        }
    
        return out;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2)流提取-cin

    思路:一个一个提取到string如果扩容的话效率太低;我们先用buff开出一定空间,先把东西存到它里面;我们再取出。

    istream& Ding::operator>>(istream& in, string& s)
    {
        s.clear();
        //当字符串很长的时候,会不断扩容,效率底。
        char ch;
        ch = in.get();//cin自动碰到' '就不读取了;我们这里使用cin.get()
    
        const size_t N = 32;
        char buff[N];
        size_t i = 0;
    
        while (ch != ' ' && ch != '\n')
        {
            buff[i++] = ch;
    
            if (i == N - 1)
            {
                buff[i] = '\0';
                s += buff;
                i = 0;
            }
            ch = in.get();
        }
        buff[i] = '\0';//字符串末尾有'\0'
        s += buff;
    
        return in;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    .
    .
    .
    感觉有所收获的话,友友们给小丁一个赞👍

  • 相关阅读:
    MMDetection库中的一些模块介绍
    xfs文件系统误删除文件恢复(testdisk工具)
    nginx反向代理,用户访问服务器1的80端口,请求转发至服务器2,3的8882端口
    密码安全:保护你的数据不被入侵的重要性
    项目1:基于Java API文档制作的搜索引擎
    设计模式---抽象工厂模式
    Shadowing Japanese Unit2
    0046_正点原子
    Cryptographic primitives(密码原语)
    ssm和springboot整合
  • 原文地址:https://blog.csdn.net/Dingyuan0/article/details/126366832