C++ String部分成員模擬實現(xiàn)流程詳解
string類的成員設計
class string
{
private:
char* _str;
int _size;
int _capacity;
};
說明:以下的五個成員函數(shù)的模擬實現(xiàn),均去除了_size 和_capacity成員變量,目的是為了更方便解釋重點。在五個成員函數(shù)模擬后,會對string類的設計進行補全。
普通構造函數(shù)的模擬
我們是否可以使用默認構造函數(shù)來初始化對象?在這種情況下是萬萬不能的!要記住默認的構造函數(shù)對自定義類型會去調用它自己的構造函數(shù)進行初始化,而對于內置類型是不做處理的,此時我們的成員變量_str的類型是內置類型,不會被初始化,所以一定要自己寫構造函數(shù)。
//這種構造函數(shù)是否可行?
string(const char* str)
{
_str = str;
}
這種寫法做不到用字符串構造一個對象。
原因:這樣會使得str和_str指向的都是同一塊空間。str會影響到_str.

所以正確的做法是,給_str分配一塊屬于自己的空間,再把str的值拷貝給_str.
string(const char* str)
{
_str = new char[strlen(str) + 1]; //要多給一個'\0'的空間
strcpy(_str, str);
}

修一下小細節(jié):
1.實例化對象的時候是支持無參構造的,所以可以給參數(shù)一個缺省值"",里面自己隱藏的有一個\0.如果沒有傳參數(shù),則使用缺省值。
string(const char* str = "")
{
_str = new char[strlen(str) + 1]; //要多給一個'\0'的空間
strcpy(_str, str);
}
拷貝構造函數(shù)的模擬
看了普通構造函數(shù)的模擬實現(xiàn)以后,最不應該犯的錯就是把一個string對象的數(shù)據(jù)直接給了另一個string對象
所以直接甩代碼
string(const string& s)
{
_str = new char[strlen(s._str) + 1];
strcpy(_str, s._str);
}當然,如果有前面所寫普通構造函數(shù),還可以利用普通構造函數(shù)來拷貝構造一個對象。
//還可以借助普通構造函數(shù)
string(const string& s)
:_str(nullptr)
{
string tmp(s._str);
swap(_str, tmp._str);
}賦值重載函數(shù)的模擬
這里重載賦值,是為了把一個已經存在的string對象的數(shù)據(jù)給另一個已經存在的string對象。
也就意味著,兩個對象均有自己的空間。不要把string對象的_str直接賦值,否則析構的時候會析構兩次,并且這兩個string對象由于_str使用的是同一塊空間,會相互之間影響。
string& operator=(const string& s)
{
delete[] _str; //把原來的空間釋放掉
_str = new char[strlen(s._str) + 1]; //給一塊新的空間
strcpy(_str, s._str);;
}
上面這種方法是不行的。
1.不排除自己給自己賦值的情況,自己都給釋放了,拿什么來賦值?
2.使用delete先釋放,只要地址正確無論如何都會釋放成功,但是new一塊空間不一定會成功,如果一開始就給釋放了,而我去申請空間卻申請不到,那就是不僅沒有賦值成功,還把我自己原本有的給丟了。
//正確的寫法
string& operator=(const string& s)
{
if (this != &s)
{
char* tmp = new char[strlen(s._str) + 1];
strcpy(tmp, s._str);
delete[] _str;
_str = tmp;
}
return *this; //如果自己給自己賦值,那就返回自己
}還可以使用傳值的方法
string& operator=(string s)
{
swap(_str, s._str);
return *this;
}

String的析構函數(shù)模擬
~string()
{
if (_str)
{
delete[] _str;
_str = nullptr;
}
}
補全上述的成員函數(shù)
//因為std庫里原本有一個string,所以這里加上一個命名空間,防止命名污染
namespace YDY
{
class string
{
public:
string(const char* str = "")
:_size(strlen(str))
,_capacity(_size)
{
_str = new char[_capacity + 1]; //要多給一個'\0'的空間
strcpy(_str, str);
}
string(const string& s)
:_str(nullptr)
,_size(s._size)
,_capacity(s._capacity)
{
string tmp(s._str);
swap(_str, tmp._str);
}
string& operator=(const string& s)
{
if (this != &s)
{
char* tmp = new char[strlen(s._str) + 1];
strcpy(tmp, s._str);
delete[] _str;
_str = tmp;
_size = s._size;
_capacity = s._capacity;
}
return *this;
}
~string()
{
if (_str)
{
delete[] _str;
_str = nullptr;
}
_size = _capacity = 0;
}
private:
char* _str;
int _size;
int _capacity;
};
void test()
{
string s1;
string s2(s1);
string s3 = s1;
}
}迭代器的簡單模擬
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;
}其他成員函數(shù)的模擬
const char* c_str()
{
return _str;
}
size_t size()
{
return _size;
}
char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
const char& operator[](size_t pos) const
{
assert(pos < _size);
return _str[pos];
}
//reserve
void reserve(size_t n)
{
if (n > _capacity)
{
//擴容到n+1
//tmp是內置類型,
char* tmp = new char[n + 1];
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = n;
}
}
//
void push_back(char c)
{
//空間不夠,擴容
if (_size == _capacity)
{
//擴容
reserve(_size + 1);
}
_str[_size] = c;
_size++;
_str[_size] = '\0';
}
void append(const char* str)
{
int len = strlen(str);
if (_size + len > _capacity)
{
//增容
reserve(_size + len);
}
strcpy(_str + _size, str);
_size += len;
}
string& operator+=(char ch)
{
push_back(ch);
return *this;
}
string& operator+=(const char* str)
{
//復用追加函數(shù)append()
append(str);
return *this;
}
//任意位置的插入
string& insert(size_t pos, char ch)
{
if (_size == _capacity)
{
reserve(_size + 1);
}
//開始插入
int end = _size + 1;
//找到pos的位置,并留出pos的位置以便插入
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);
}
//找到pos的位置,并且留出要插入的位置
size_t end = _size + len;
while (end > pos)
{
_str[end] = _str[end - len];
end--;
}
//開始插入
strncpy(_str + pos, str, len);
return *this;
}
//從pos的位置開始刪除len的長度
string& erase(size_t pos = 0, size_t len = std::string::npos)
{
assert(pos < _size);
if (len == std::string::npos || pos + len > _size)
{
_str[pos] = '\0';
_size = pos;
}
else
{
strcpy(_str + pos, _str + pos + len);
_size -= len;
}
return *this;
}到此這篇關于C++ String部分成員模擬實現(xiàn)流程詳解的文章就介紹到這了,更多相關C++ String成員模擬實現(xiàn)內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java C++ 題解leetcode1619刪除某些元素后數(shù)組均值
這篇文章主要為大家介紹了Java C++ 題解leetcode1619刪除某些元素后數(shù)組均值示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-09-09
C++利用stringstream進行數(shù)據(jù)類型轉換實例
這篇文章主要介紹了C++利用stringstream進行數(shù)據(jù)類型轉換的方法,實例分析了使用stringstream進行string轉int的操作技巧,需要的朋友可以參考下2015-01-01

