綏化網(wǎng)站建設(shè)站長(zhǎng)工具關(guān)鍵詞挖掘
文章目錄
- 一. string底層邏輯
- 演示聲明和定義分開(kāi)
- 二. size()
- 三. operator[]
- 四. 迭代器
- 四. const迭代器
- 五. 預(yù)留空間(reserve)
- 六. 尾插一個(gè)字符push_back
- 七. 尾插一個(gè)字符串a(chǎn)ppend
- 八. operator+=
- 九. operator+=
一. string底層邏輯
(1)為了和庫(kù)里面的string類區(qū)分開(kāi),我們可以使用命名空間(hou)。之前學(xué)習(xí)的命名空間就有了價(jià)值。
(2)在類里面的都是內(nèi)聯(lián)函數(shù)
(3)對(duì)于比較短小的函數(shù),直接在類里面寫(xiě)就行。函數(shù)大一點(diǎn),將聲明和定義分開(kāi)。
- 成員變量
#include<stdio.h>
#include<string>
#include<iostream>
namespace hou
{class string{private:char* _str; //char類型數(shù)據(jù)數(shù)組的地址size_t _size; //有效元素個(gè)數(shù)size_t _capacity; //空間大小};
}
- 成員函數(shù)
任何一個(gè)類都從構(gòu)造函數(shù)開(kāi)始(無(wú)參/有參)
無(wú)參的話,將三個(gè)成員變量初始化為什么呢?都初始化為空嗎?
這樣是不可以的。
記得:const char*
比較特殊,cout
它不會(huì)打印出地址,它自動(dòng)識(shí)別類型,會(huì)以為打印字符串(字符串的打印規(guī)則是遇到‘\0’
才會(huì)終止),而我們的_str
是空指針,將空指針解引用,肯定是錯(cuò)誤的(本質(zhì)是空指針問(wèn)題)
---------------
所以,不能將char*
初始化為空。里面起碼要放一個(gè)'\0'
namespace hou
{class string{public://任何一個(gè)類都從構(gòu)造函數(shù)開(kāi)始string()//先寫(xiě)一個(gè)無(wú)參的構(gòu)造函數(shù):_str(new char[1]{'\0'}),_size(0),_capacity(0){}~string(){delete[] _str;_str = nullptr;_size = 0;_capacity = 0;}const char* c_str()const{return _str;}private:char* _str; //char類型數(shù)據(jù)數(shù)組的地址size_t _size; //有效元素個(gè)數(shù)size_t _capacity; //空間大小};
}
剛剛寫(xiě)了無(wú)參的構(gòu)造函數(shù),接下來(lái)寫(xiě)一個(gè)有參的構(gòu)造函數(shù)
注意點(diǎn):
strlen
計(jì)算長(zhǎng)度時(shí),不包括'\0'
- strlen是在運(yùn)行時(shí)計(jì)算的,size是編譯時(shí)計(jì)算的
- 在初始化列表里寫(xiě),它的初始化順序是按照聲明的順序來(lái)的
之前我們說(shuō)過(guò),盡可能使用初始化列表,但是strlen是在運(yùn)行時(shí)計(jì)算的,要計(jì)算3次,效率低。這樣子的話,我們可以將strlen先計(jì)算出來(lái),之后用。但記住,初始化列表的順序是按照聲明的順序。
演示聲明和定義分開(kāi)
當(dāng)我們想把聲明寫(xiě)在.h里面,定義寫(xiě)在.cpp里面的時(shí)候
這樣寫(xiě)會(huì)報(bào)錯(cuò),所以我們需要在string.cpp
里(1)寫(xiě)上類域(2)再寫(xiě)一下命名空間
一個(gè)命名空間是可以寫(xiě)多個(gè)的,多個(gè)文件的同一個(gè)命名空間會(huì)被合并為(認(rèn)為)一個(gè)命名空間的
已經(jīng)聲明和定義了,還有一個(gè)需要注意的內(nèi)容是,缺省值只能在聲明的時(shí)候給(定義那里不可以寫(xiě)缺省值)。但是char* _str
的缺省值不可以是nullptr
,可以給一個(gè)'\0'
或者直接“”
(字符串默認(rèn)后面會(huì)加'\0'
的)
二. size()
對(duì)象.size()
就是為了得到對(duì)象的大小(即對(duì)象的有效元素個(gè)數(shù))
如果聲明和定義分開(kāi)寫(xiě)了,同時(shí)這個(gè)函數(shù)有返回值,那string::
加到哪里呢?
三. operator[]
string.cpp里面的內(nèi)容
char& string::operator[](size_t i)
{return _str[i];
}
四. 迭代器
string的迭代器(string的物理結(jié)構(gòu)是數(shù)組)
using iterator = char*;
//typedef char* iterator;
迭代器還需要配合begin()
和end()
(begin()就是返回開(kāi)始位置的迭代器)
using iterator = char*;
iterator string::begin()
{return _str;
}
iterator string::end()
{return _str+_size;
}
范圍for的底層是迭代器(支持迭代器則支持范圍for)
四. const迭代器
五. 預(yù)留空間(reserve)
本質(zhì)就是擴(kuò)容,但是這種提高了效率,原本需要2倍2倍的擴(kuò),但是當(dāng)你知道需要多大的空間時(shí),就可以一次性擴(kuò)容好。
- reserve一般不縮容,我們需要先判斷一下,想擴(kuò)容的大小n是否比_capacity大
- 開(kāi)空間的時(shí)候永遠(yuǎn)要多開(kāi)一個(gè),因?yàn)?code>’\0‘是不計(jì)入
_capacity
的
void string:: reserve(size_t n){if (n > _capacity){char* tmp=new char[n+1];strcpy(tmp, _str);delete[]_str;_str = tmp;_capacity = n; //'\0'不計(jì)入空間大小}}
六. 尾插一個(gè)字符push_back
void string::push_back(char ch)
{//先判斷空間大小是否足夠if (_size = _capacity){//不夠的話進(jìn)入if語(yǔ)句進(jìn)行擴(kuò)容reserve(_capacity = 0 ? 4 : 2 * _capacity);}_str[_size] = ch;_size++;
}
七. 尾插一個(gè)字符串a(chǎn)ppend
void string::append(const char* str){size_t len = strlen(str);size_t newcapacity = 2 * _capacity < _size + len ? _size + len : 2 * _capacity;reserve(newcapacity);//開(kāi)好空間之后,插入字符串strcpy(_str+_size, str);//直接復(fù)制(第一個(gè)參數(shù)是復(fù)制到哪里(位置),第二個(gè)是被復(fù)制的串)_size += len;}
八. operator+=
string& string:: operator+=(char ch)
{push_back(ch);return *this;
}
九. operator+=
string& string:: operator+=(const char* str)
{append(str);return *this;
}