C++初阶之一篇文章让你掌握string类(模拟实现)(下)

简介: 7.8 string类insert函数、append函数、push_back函数、+=重载insert函数insert的模拟实现主要实现字符和字符串插入两种

7.8 string类insert函数、append函数、push_back函数、+=重载

insert函数

insert的模拟实现主要实现字符和字符串插入两种

字符插入

string& insert(size_t pos, char ch)
{
  assert(pos <= _size);
  // 满了就扩容
  if (_size == _capacity)
  {
    reserve(_capacity == 0 ? 4 : _capacity * 2);
  }
  size_t end = _size + 1;
  while (end > pos)
  {
    _str[end] = _str[end - 1];
    --end;
  }
  _str[pos] = ch;
  ++_size;
  return *this;
}

insert 函数在字符串中指定位置插入一个字符。这里简单解释一下这个函数的实现:

string& insert(size_t pos, char ch):这是 std::string 类中的 insert 函数的声明,表示该函数将在指定位置 pos 插入字符 ch。pos 是传入的参数,表示插入位置的索引;ch 是要插入的字符。

assert(pos <= _size);:使用 assert 断言来确保插入位置 pos 不超过字符串的实际大小 _size。如果断言失败(pos 大于 _size),则会触发断言失败错误,帮助调试找到错误的位置。

if (_size == _capacity):检查当前字符串是否已满(即 _size 等于 _capacity)。如果字符串已满,则需要扩容,以确保有足够的容量来插入新字符。这里使用 reserve 函数扩容,使字符串有足够的容量来容纳新字符。

size_t end = _size + 1;:在插入字符前,先将字符串的末尾位置(实际字符个数 _size 后面)向后移动一个位置,为新字符留出空间。这样做是为了将插入位置 pos 之后的字符后移。

while (end > pos):通过一个循环,将插入位置 pos 之后的字符依次向后移动一个位置。

_str[pos] = ch;:将字符 ch 插入到指定的插入位置 pos。

++_size;:插入字符后,将字符串的实际大小 _size 增加 1。

return *this;:返回当前 std::string 对象的引用,以支持链式调用。

字符串插入

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 + len)
  {
    _str[end] = _str[end - len];
    --end;
  }
  strncpy(_str + pos, str, len);
  _size += len;
  return *this;
}

与上一个 insert 函数相比,这里的参数 str 是一个 C-style 字符串(const char*),而不是一个单个字符。函数的功能是在字符串中指定位置插入一个 C-style 字符串。现在来解释这个函数的实现:

string& insert(size_t pos, const char* str):这是 std::string 类中的 insert 函数的声明,表示该函数将在指定位置 pos 插入一个 C-style 字符串 str。pos 是传入的参数,表示插入位置的索引;str 是要插入的 C-style 字符串。

assert(pos <= _size);:使用 assert 断言来确保插入位置 pos 不超过字符串的实际大小 _size。如果断言失败(pos 大于 _size),则会触发断言失败错误,帮助调试找到错误的位置。

size_t len = strlen(str);:计算要插入的 C-style 字符串 str 的长度,即字符个数。

if (_size + len > _capacity):检查插入后的字符串大小是否超过当前的容量 _capacity,如果超过,则需要扩容,以确保有足够的容量来容纳插入的字符串。

reserve(_size + len);:调用 reserve 函数来扩容,保证有足够的容量来容纳插入的字符串。

size_t end = _size + len;:在插入字符串前,先将字符串的末尾位置(实际字符个数 _size 后面)向后移动 len 个位置,为新字符串留出空间。

while (end >= pos + len):通过一个循环,将插入位置 pos 之后的字符依次向后移动 len 个位置,为新字符串的插入留出空间。

strncpy(_str + pos, str, len);:使用 strncpy 函数将 C-style 字符串 str 复制到指定的插入位置 pos,并且只复制 len 个字符。

_size += len;:插入字符串后,将字符串的实际大小 _size 增加 len,以反映插入后的新大小。

return *this;:返回当前 std::string 对象的引用,以支持链式调用。

append函数

void append(const char* str)
{
  size_t len = strlen(str);
  // 满了就扩容
  if (_size + len > _capacity)
  {
    reserve(_size+len);
  }
  strcpy(_str + _size, str);
  //strcat(_str, str); 需要找\0,效率低
  _size += len;
}

append 函数用于在字符串末尾添加一个 C-style 字符串。现在来解释这个函数的实现:

void append(const char* str):这是 std::string 类中的 append 函数的声明,表示该函数将在字符串末尾添加一个 C-style 字符串 str。str 是传入的参数,表示要添加的 C-style 字符串。

size_t len = strlen(str);:计算要添加的 C-style 字符串 str 的长度,即字符个数。

if (_size + len > _capacity):检查添加后的字符串大小是否超过当前的容量 _capacity,如果超过,则需要扩容,以确保有足够的容量来容纳添加的字符串。

reserve(_size + len);:调用 reserve 函数来扩容,保证有足够的容量来容纳添加的字符串。

strcpy(_str + _size, str);:使用 strcpy 函数将 C-style 字符串 str 复制到字符串末尾,即从 _str 的实际字符个数 _size 处开始复制。

_size += len;:添加字符串后,将字符串的实际大小 _size 增加 len,以反映添加后的新大小。

这样,append 函数将 C-style 字符串 str 添加到字符串末尾,并且在必要时进行了内存扩容。

当然你可以对insert函数复用

void append(const char* str)
{
  insert(_size, str);
}

push_back函数

void push_back(char ch)
{
  // 满了就扩容
  if (_size == _capacity)
  {
    reserve(_capacity == 0 ? 4 : _capacity * 2);
  }
  _str[_size] = ch;
  ++_size;
  _str[_size] = '\0';
}

push_back 函数用于在字符串末尾添加一个字符。现在来解释这个函数的实现:

void push_back(char ch):这是 std::string 类中的 push_back 函数的声明,表示该函数将在字符串末尾添加一个字符 ch。ch 是传入的参数,表示要添加的字符。

if (_size == _capacity):检查当前字符串是否已满(即 _size 等于 _capacity)。如果字符串已满,则需要扩容,以确保有足够的容量来容纳新增的字符。这里使用 reserve 函数扩容,使字符串有足够的容量来容纳新字符。

_str[_size] = ch;:将字符 ch 添加到字符串末尾,即在 _str 的实际字符个数 _size 处添加字符。

++_size;:字符串的实际大小 _size 增加 1,以反映添加后的新大小。

_str[_size] = '\0';:在字符串末尾添加一个空字符 ‘\0’,以保证新的字符串正确终止。

这样,push_back 函数将字符 ch 添加到字符串末尾,并在必要时进行了内存扩容。

同样的,push_back 函数你也可以对insert函数复用

void push_back(char ch)
{
  insert(_size, ch);
}

+=重载

string& operator+=(char ch)
{
  push_back(ch);
  return *this;
}
string& operator+=(const char* str)
{
  append(str);
  return *this;
}

operator+= 运算符重载用于在现有字符串后追加字符或 C-style 字符串。现在来解释这个函数的实现:

string& operator+=(char ch):这是 operator+= 运算符重载的第一个版本,表示该运算符将在字符串末尾追加一个字符 ch。在这个版本中,直接调用了 push_back 函数,将字符 ch 添加到字符串末尾。

string& operator+=(const char* str):这是 operator+= 运算符重载的第二个版本,表示该运算符将在字符串末尾追加一个 C-style 字符串 str。在这个版本中,直接调用了 append 函数,将 C-style 字符串 str 添加到字符串末尾。

在两个版本的实现中,都返回当前 std::string 对象的引用,以支持链式调用。

7.9 string类erase函数

void erase(size_t pos, size_t len = npos)
{
  assert(pos < _size);
  if (len == npos || pos + len >= _size)
  {
    _str[pos] = '\0';
    _size = pos;
  }
  else
  {
    strcpy(_str + pos, _str + pos + len);
    _size -= len;
  }
}

erase 函数用于从字符串中删除指定位置开始的一定长度的字符。现在来解释这个函数的实现:

void erase(size_t pos, size_t len = npos):这是 std::string 类中的 erase 函数的声明,表示该函数将从指定位置 pos 开始删除一定长度 len 的字符。pos 是传入的参数,表示删除的起始位置的索引;len 是要删除的字符个数,默认值为 npos,表示删除从起始位置开始的所有字符。

assert(pos < _size);:使用 assert 断言来确保删除的起始位置 pos 不超过字符串的实际大小 _size。如果断言失败(pos 大于等于 _size),则会触发断言失败错误,帮助调试找到错误的位置。

if (len == npos || pos + len >= _size):检查是否要删除从起始位置 pos 开始的所有字符(即 len 等于 npos),或者是否要删除的字符个数超过字符串末尾(即 pos + len 大于等于 _size)。如果是其中一种情况,表示要删除从 pos 开始的所有字符或从 pos 开始直到末尾的所有字符。

_str[pos] = '\0'; 和 _size = pos;:在上述情况下,将字符串从位置 pos 处截断,即将字符数组的第 pos 个字符设置为空字符 ‘\0’,并更新字符串的实际大小 _size 为 pos,以反映删除后的新大小。

else:如果要删除的字符个数小于字符串末尾的字符个数,则需要将后面的字符向前移动。

strcpy(_str + pos, _str + pos + len);:将从位置 pos + len 开始的字符复制到位置 pos,覆盖掉要删除的字符。

_size -= len;:删除字符后,将字符串的实际大小 _size 减去 len,以反映删除后的新大小。

7.10 string类erase函数

size_t find(char ch, size_t pos = 0) const
{
  assert(pos < _size);
  for (size_t i = pos; i < _size; ++i)
  {
    if (ch == _str[i])
    {
      return i;
    }
  }
  return npos;
}

find 函数用于在字符串中查找指定字符或子串,并返回其位置。现在来解释这个函数的实现:

size_t find(char ch, size_t pos = 0) const:这是 std::string 类中的 find 函数的第一个版本,表示该函数将在字符串中从位置 pos 开始查找字符 ch。pos 是传入的参数,表示查找的起始位置的索引,默认值为 0,表示从字符串的开头开始查找。

assert(pos < _size);:使用 assert 断言来确保查找的起始位置 pos 不超过字符串的实际大小 _size。如果断言失败(pos 大于等于 _size),则会触发断言失败错误,帮助调试找到错误的位置。

在这个版本中,使用了简单的循环遍历,从位置 pos 开始遍历字符串,查找是否存在字符 ch。如果找到了,就返回该字符的位置索引;如果未找到,则返回 npos。

size_t find(const char* sub, size_t pos = 0) const
{
  assert(sub);
  assert(pos < _size);
  const char* ptr = strstr(_str + pos, sub);
  if (ptr == nullptr)
  {
    return npos;
  }
  else
  {
    return ptr - _str;
  }
}

size_t find(const char* sub, size_t pos = 0) const:这是 std::string 类中的 find 函数的第二个版本,表示该函数将在字符串中从位置 pos 开始查找子串 sub。sub 是传入的参数,表示要查找的子串;pos 是传入的参数,表示查找的起始位置的索引,默认值为 0,表示从字符串的开头开始查找。

assert(sub);:使用 assert 断言来确保传入的子串 sub 不为空指针。如果断言失败(sub 为空指针),则会触发断言失败错误,帮助调试找到错误的位置。

assert(pos < _size);:同样,使用 assert 断言来确保查找的起始位置 pos 不超过字符串的实际大小 _size。

在这个版本中,使用 strstr 函数在字符串中查找子串 sub,如果找到了,就返回子串的位置索引;如果未找到,则返回 npos。

7.11 string类substr 函数

string substr(size_t pos, size_t len = npos) const
{
  assert(pos < _size);
  size_t realLen = len;
  if (len == npos || pos + len > _size)
  {
    realLen = _size - pos;
  }
  string sub;
  for (size_t i = 0; i < realLen; ++i)
  {
    sub += _str[pos + i];
  }
  return sub;
}

substr 函数用于从字符串中提取子串,从指定位置 pos 开始,并且可选地指定子串的长度 len。现在来解释这个函数的实现:

string substr(size_t pos, size_t len = npos) const:这是 std::string 类中的 substr 函数的声明,表示该函数将从指定位置 pos 开始提取子串,并且可选地指定子串的长度 len。pos 是传入的参数,表示提取子串的起始位置的索引;len 是传入的参数,表示要提取的子串的长度,默认值为 npos,表示提取从起始位置 pos 开始的所有字符。

assert(pos < _size);:使用 assert 断言来确保提取子串的起始位置 pos 不超过字符串的实际大小 _size。如果断言失败(pos 大于等于 _size),则会触发断言失败错误,帮助调试找到错误的位置。

size_t realLen = len;:定义一个变量 realLen,用于存储实际要提取的子串的长度。初始值为传入的参数 len。

if (len == npos || pos + len > _size):检查是否要提取从起始位置 pos 开始的所有字符(即 len 等于 npos),或者是否要提取的字符个数超过字符串末尾(即 pos + len 大于等于 _size)。如果是其中一种情况,表示要提取从 pos 开始的所有字符或从 pos 开始直到末尾的所有字符。此时,将 realLen 更新为从 pos 开始到末尾的字符个数。创建一个名为 sub 的新的 std::string 对象,用于存储提取的子串。使用循环从位置 pos 开始,逐个字符地将子串添加到 sub 中。返回提取的子串 sub。

7.12 string类比较运算符重载

bool operator>(const string& s) const
{
  return strcmp(_str, s._str) > 0;
}

这是大于运算符 > 的重载版本,表示该运算符用于比较当前字符串与另一个字符串 s 的大小关系。在这个版本中,使用 strcmp 函数比较两个字符串 _str 和 s._str 的字典序。如果 _str 大于 s._str,则返回 true,否则返回 false。

bool operator==(const string& s) const
{
  return strcmp(_str, s._str) == 0;
}

这是等于运算符 == 的重载版本,表示该运算符用于比较当前字符串与另一个字符串 s 是否相等。同样,使用 strcmp 函数比较两个字符串 _str 和 s._str 的内容是否相同。如果相同,返回 true,否则返回 false。

bool operator>=(const string& s) const
{
  return *this > s || *this == s;
}

这是大于等于运算符 >= 的重载版本,表示该运算符用于比较当前字符串是否大于或等于另一个字符串 s。在这个版本中,直接使用已经定义好的大于运算符 > 和等于运算符 == 进行组合,如果当前字符串大于 s 或者与 s 相等,则返回 true,否则返回 false。

bool operator<=(const string& s) const
{
  return !(*this > s);
}

这是小于等于运算符 <= 的重载版本,表示该运算符用于比较当前字符串是否小于或等于另一个字符串 s。同样,直接使用已经定义好的大于等于运算符 >= 进行取反,如果当前字符串小于 s,则返回 true,否则返回 false。

bool operator<(const string& s) const
{
  return !(*this >= s);
}

这是小于运算符 < 的重载版本,表示该运算符用于比较当前字符串是否小于另一个字符串 s。同样,直接使用已经定义好的大于等于运算符 >= 进行取反,如果当前字符串不大于等于 s,则说明当前字符串小于 s,返回 true,否则返回 false。

bool operator!=(const string& s) const
{
  return !(*this == s);
}

这是不等于运算符 != 的重载版本,表示该运算符用于比较当前字符串是否不等于另一个字符串 s。同样,直接使用已经定义好的等于运算符 == 进行取反,如果当前字符串与 s 不相等,则返回 true,否则返回 false。

其实和之前类和对象的文章中讲到的日期类比较运算符重载一样,先实现> ==< ==后面的都可以进行复用。

7.13 string类流插入<<和流提取>>重载

首先这里要注意的是,流插入和流提取在这里定义为全局函数,因此我们不要再类中定义,而是在类外,即全局定义。这样定义的运算符重载函数不属于类的成员,因此在其实现中不能直接访问类的私有成员,而需要通过类的公有接口进行访问。

运算符重载函数可以作为成员函数或全局非成员函数进行定义,具体取决于使用场景和设计需求。通常情况下,如果运算符的操作数为类对象本身或需要直接访问类的私有成员,可以考虑将其定义为成员函数。而如果运算符的操作数为类对象外的其他类型,或者运算符涉及的操作不仅限于类对象本身,可以考虑将其定义为全局非成员函数

流插入<<

ostream& operator<<(ostream& out, const string& s)
{
  for (size_t i = 0; i < s.size(); ++i)
  {
    out << s[i];
  }
  return out;
}

这是输出运算符 << 的重载版本,表示将 std::string 类对象 s 输出到输出流 out 中。

使用一个循环遍历 s 中的每个字符,并将每个字符依次输出到输出流 out 中。最后,将输出流 out 返回,以支持链式输出。

istream& operator>>(istream& in, string& s)
{
  s.clear();
  char ch;
  ch = in.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';
  s += buff;
  return in;
}

这是输入运算符 >> 的重载版本,表示将输入流 in 中的数据读取并存储到 std::string 类对象 s 中。

首先调用 s.clear() 函数,将 s 的内容清空,以便接收新的输入。然后,使用一个循环从输入流 in 中逐个读取字符 ch。如果字符 ch 不是空格或换行符,就将字符添加到一个临时字符数组 buff 中,并增加索引 i。一旦 buff 已满(i == N - 1),就将 buff 最后一个元素设为空字符 ‘\0’,然后将 buff 添加到 s 中,然后将索引 i 重置为 0,以继续接收后续字符。如果字符 ch 是空格或换行符,说明一个单词的输入结束,将 buff 最后一个元素设为空字符 ‘\0’,然后将 buff 添加到 s 中。最后,将输入流 in 返回,以支持链式输入。

8.string类的模拟实现(完整代码)

#include<iostream>
#include<string.h>
#include<assert.h>
using namespace std;
namespace mystring
{
  class string
  {
  public:
    typedef char* iterator;
    typedef const char* const_iterator;
    iterator begin()
    {
      return _str;
    }
    iterator end()
    {
      return _str + _size;
    }
    const_iterator begin() const
    {
      return _str;
    }
    const_iterator end() const
    {
      return _str + _size;
    }
    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& operator=(const string& s)
    //{
    //  if (this != &s)
    //  {
    //    //string tmp(s._str);
    //    string tmp(s);
    //    swap(tmp); // this->swap(tmp);
    //  }
    //  return *this;
    //}
    string& operator=(string s)
    {
      swap(s);
      return *this;
    }
    ~string()
    {
      delete[] _str;
      _str = nullptr;
      _size = _capacity = 0;
    }
    const char* c_str() const
    {
      return _str;
    }
    size_t size() const
    {
      return _size;
    }
    size_t capacity() const
    {
      return _capacity;
    }
    const char& operator[](size_t pos) const
    {
      assert(pos < _size);
      return _str[pos];
    }
    char& operator[](size_t pos)
    {
      assert(pos < _size);
      return _str[pos];
    }
    void reserve(size_t n)
    {
      if (n > _capacity)
      {
        char* tmp = new char[n + 1];
        strcpy(tmp, _str);
        delete[] _str;
        _str = tmp;
        _capacity = n;
      }
    }
    void resize(size_t n, char ch = '\0')
    {
      if (n > _size)
      {
        // 插入数据
        reserve(n);
        for (size_t i = _size; i < n; ++i)
        {
          _str[i] = ch;
        }
        _str[n] = '\0';
        _size = n;
      }
      else
      {
        // 删除数据
        _str[n] = '\0';
        _size = n;
      }
    }
    void push_back(char ch)
    {
      // 满了就扩容
      if (_size == _capacity)
      {
        reserve(_capacity == 0 ? 4 : _capacity * 2);
      }
      _str[_size] = ch;
      ++_size;
      _str[_size] = '\0';
      //insert(_size, ch);
    }
    void append(const char* str)
    {
      size_t len = strlen(str);
      // 满了就扩容
      if (_size + len > _capacity)
      {
        reserve(_size+len);
      }
      strcpy(_str + _size, str);
      //strcat(_str, str); 需要找\0,效率低
      _size += len;
      //insert(_size, str);
    }
    string& operator+=(char ch)
    {
      push_back(ch);
      return *this;
    }
    string& operator+=(const char* str)
    {
      append(str);
      return *this;
    }
    string& insert(size_t pos, char ch)
    {
      assert(pos <= _size);
      // 满了就扩容
      if (_size == _capacity)
      {
        reserve(_capacity == 0 ? 4 : _capacity * 2);
      }
      size_t end = _size + 1;
      while (end > pos)
      {
        _str[end] = _str[end - 1];
        --end;
      }
      _str[pos] = ch;
      ++_size;
      return *this;
    }
    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 + len)
      {
        _str[end] = _str[end - len];
        --end;
      }
      strncpy(_str + pos, str, len);
      _size += len;
      return *this;
    }
    void erase(size_t pos, size_t len = npos)
    {
      assert(pos < _size);
      if (len == npos || pos + len >= _size)
      {
        _str[pos] = '\0';
        _size = pos;
      }
      else
      {
        strcpy(_str + pos, _str + pos + len);
        _size -= len;
      }
    }
    void clear()
    {
      _str[0] = '\0';
      _size = 0;
    }
    size_t find(char ch, size_t pos = 0) const
    {
      assert(pos < _size);
      for (size_t i = pos; i < _size; ++i)
      {
        if (ch == _str[i])
        {
          return i;
        }
      }
      return npos;
    }
    size_t find(const char* sub, size_t pos = 0) const
    {
      assert(sub);
      assert(pos < _size);
      // kmp/bm
      const char* ptr = strstr(_str + pos, sub);
      if (ptr == nullptr)
      {
        return npos;
      }
      else
      {
        return ptr - _str;
      }
    }
    string substr(size_t pos, size_t len = npos) const
    {
      assert(pos < _size);
      size_t realLen = len;
      if (len == npos || pos + len > _size)
      {
        realLen = _size - pos;
      }
      string sub;
      for (size_t i = 0; i < realLen; ++i)
      {
        sub += _str[pos + i];
      }
      return sub;
    }
    bool operator>(const string& s) const
    {
      return strcmp(_str, s._str) > 0;
    }
    bool operator==(const string& s) const
    {
      return strcmp(_str, s._str) == 0;
    }
    bool operator>=(const string& s) const
    {
      return *this > s || *this == s;
    }
    bool operator<=(const string& s) const
    {
      return !(*this > s);
    }
    bool operator<(const string& s) const
    {
      return !(*this >= s);
    }
    bool operator!=(const string& s) const
    {
      return !(*this == s);
    }
  private:
    size_t _capacity;
    size_t _size;
    char* _str;
  public:
    const static size_t npos = -1;
  };
  ostream& operator<<(ostream& out, const string& s)
  {
    for (size_t i = 0; i < s.size(); ++i)
    {
      out << s[i];
    }
    return out;
  }
  istream& operator>>(istream& in, string& s)
  {
    s.clear();
    char ch;
    ch = in.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';
    s += buff;
    return in;
  }
}

结语

有兴趣的小伙伴可以关注作者,如果觉得内容不错,请给个一键三连吧,蟹蟹你哟!!!

制作不易,如有不正之处敬请指出

感谢大家的来访,UU们的观看是我坚持下去的动力

在时间的催化剂下,让我们彼此都成为更优秀的人吧!!!


相关文章
|
22小时前
|
存储 编译器 Linux
C++初阶学习第十弹——探索STL奥秘(五)——深入讲解vector的迭代器失效问题
C++初阶学习第十弹——探索STL奥秘(五)——深入讲解vector的迭代器失效问题
15 7
|
22小时前
|
程序员 C++
C++初阶学习第七弹——探索STL奥秘(二)——string的模拟实现
C++初阶学习第七弹——探索STL奥秘(二)——string的模拟实现
10 1
|
22小时前
|
C语言 C++
C++初阶学习第六弹——探索STL奥秘(一)——标准库中的string类
C++初阶学习第六弹——探索STL奥秘(一)——标准库中的string类
|
22小时前
|
C++
C++初阶学习第五弹——类与对象(下)——类与对象的收官战
C++初阶学习第五弹——类与对象(下)——类与对象的收官战
|
23小时前
|
编译器 C++
C++初阶学习第四弹——类与对象(中)——刨析类与对象的核心点
C++初阶学习第四弹——类与对象(中)——刨析类与对象的核心点
|
23小时前
|
C语言 C++
C++初阶学习第三弹——类与对象(上)——初始类与对象
C++初阶学习第三弹——类与对象(上)——初始类与对象
|
23小时前
|
C语言 C++
C++初阶学习第一弹——C++入门(上)
C++初阶学习第一弹——C++入门(上)
|
1天前
|
编译器 C++
C++进阶之路:何为运算符重载、赋值运算符重载与前后置++重载(类与对象_中篇)
C++进阶之路:何为运算符重载、赋值运算符重载与前后置++重载(类与对象_中篇)
5 1
|
3天前
|
存储 编译器 C++
3.C++类和对象(中)
3.C++类和对象(中)
|
3天前
|
存储 编译器 C语言
【C++语言2】类和对象(上)
【C++语言2】类和对象(上)