亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C++模擬實(shí)現(xiàn)string的示例代碼

 更新時(shí)間:2022年11月17日 08:18:45   作者:蔣靈瑜的筆記本  
這篇文章主要為大家詳細(xì)介紹了C++模擬實(shí)現(xiàn)string的相關(guān)資料,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)C++有一定的幫助,需要的可以參考一下

一、std::swap和std::string::swap的區(qū)別

如果用std::swap交換兩個(gè)string對象,將會(huì)發(fā)生1次構(gòu)造和2次賦值,也就是三次深拷貝;而使用std::string::swap僅交換成員,代價(jià)較小。

二、string的默認(rèn)構(gòu)造函數(shù)

1、構(gòu)造函數(shù)

string(const char* s = "")
{
    _size = strlen(s);//_size和_capacity均不包含'\0'
    _capacity = _size;
    _arr = new char[_size + 1];
    memcpy(_arr, s, _size + 1);
}

構(gòu)造函數(shù)用缺省值,能夠滿足空串的構(gòu)造。

這里設(shè)計(jì)_size和_capacity均不包含'\0'。_arr的空間多new一個(gè),用于儲(chǔ)存'\0'。

再將形參的內(nèi)存拷貝至_arr中,即可完成構(gòu)造。

2、拷貝構(gòu)造

寫法1:老老實(shí)實(shí)的根據(jù)string對象的私有變量進(jìn)行拷貝構(gòu)造。

string(const string& s)
{
    _size = s._size;//_size和_capacity均不包含'\0'
    _capacity = s._capacity;
    _arr = new char[_capacity + 1];
    memcpy(_arr, s._arr, _capacity + 1);
}

寫法2:通過構(gòu)造一個(gè)臨時(shí)對象,將這個(gè)臨時(shí)對象的私有變量全部和*this的私有變量交換。

注意拷貝構(gòu)造需要先將_arr初始化為nullptr,防止后續(xù)tmp拿到隨機(jī)地址。(tmp銷毀將調(diào)用析構(gòu)函數(shù),對一塊隨機(jī)地址的空間進(jìn)行析構(gòu)程序?qū)?huì)崩潰)

void swap(string& s)
{
    std::swap(_arr, s._arr);
    std::swap(_size, s._size);
    std::swap(_capacity, s._capacity);
}
string(const string& s)
    :_arr(nullptr)//防止交換后tmp._arr為隨機(jī)值,析構(gòu)出錯(cuò)
{
    string tmp(s.c_str());//構(gòu)造
    swap(tmp);
}

3、賦值運(yùn)算符重載

寫法1:同樣的老實(shí)人寫法。這種寫法要防止自己給自己賦值!

string& operator=(const string& s)
{
    if (this != &s)//防止自己給自己賦值
    {
        _size = s._size;
        _capacity = s._capacity;
        char* tmp = new char[_capacity + 1];
        delete[] _arr;
        _arr = tmp;
        memcpy(_arr, s._arr, _capacity + 1);
    }
    return *this;
}

寫法2:通過構(gòu)造臨時(shí)變量tmp,完成賦值。這種寫法無需擔(dān)心自己給自己賦值的情況,并且_arr無需初始化為nullptr。 

void swap(string& s)
{
    std::swap(_arr, s._arr);
    std::swap(_size, s._size);
    std::swap(_capacity, s._capacity);
}
string& operator=(const string& s)
{
    string tmp(s.c_str());//構(gòu)造
    swap(tmp);
    return *this;
}

4、析構(gòu)函數(shù)

~string()
{
    _size = _capacity = 0;
    delete[] _arr;
    _arr = nullptr;
}

三、string中的小接口

//string的size()接口
size_t size()const//右const修飾*this,這樣const和非const對象均可調(diào)用
{
    return _size;
}
//string的c_str()接口
const char* c_str()const
{
    return _arr;
}
//string的capacity()接口
size_t capacity()const
{
    return _capacity;
}
//string的clear()接口
void clear()
{
    _arr[0] = '\0';
    _size = 0;
}
//string的判空
bool empty()const
{
    return _size == 0 ? false : true;
}

如果函數(shù)形參不發(fā)生改變的,無腦加const修飾。

只有指針和引用會(huì)有const權(quán)限問題。

四、遍歷接口的實(shí)現(xiàn)

1、對operator[]進(jìn)行重載

char& operator[](size_t pos)//普通對象,可讀可寫
{
    assert(pos < _size);
    return _arr[pos];
}
const char& operator[](size_t pos)const//const對象,僅讀
{
    assert(pos < _size);
    return _arr[pos];
}

讓字符串進(jìn)行下標(biāo)式的訪問,需要重載兩個(gè)operator[]函數(shù),正常對象去調(diào)可讀可寫,const對象調(diào)用只讀。

2、迭代器

typedef char* iterator;
iterator begin()
{
    return _arr;
}
iterator end()//end指向字符串的'\0'
{
    return _arr + _size;
}

string的迭代器是字符指針,寫完迭代器就可以用迭代器實(shí)現(xiàn)訪問、修改了。

范圍for的底層也是一個(gè)迭代器,但是范圍for底層只認(rèn)begin()和end(),如果和自己實(shí)現(xiàn)的迭代器接口名稱對不上,那么范圍for將無法使用。

五、reserve和resize

//sring的reserve接口, 如果預(yù)開空間小于現(xiàn)有空間,將不會(huì)改變?nèi)萘俊?
void reserve(size_t n = 0)
{
    if (n + 1 > _capacity)
    {
        char* tmp = new char[n + 1];
        memset(tmp, '\0', n + 1);
        memcpy(tmp, _arr, _size);
        delete[] _arr;
        _arr = tmp;
        _capacity = n;
    }
}
//sring的resize接口
void resize(size_t n, char c)
{
    //判斷n的大小
    if (n > _capacity)
    {
        reserve(n);
        memset(_arr + _size, c, n - _size);
        _size = n;
    }
    else
    {
        _arr[n] = '\0';
        _size = n;
    }
}

reserve是擴(kuò)容,可以用于預(yù)開空間,防止頻繁的空間申請。申請一塊n+1大小的空間,將該空間全部初始化'\0',再將_arr中的數(shù)據(jù)拷貝至tmp中,釋放_(tái)arr,_arr指向tmp。

在resize中需要考慮_size擴(kuò)容和縮容的問題。

六、插入刪除查找相關(guān)接口

1、push_back、append、+=

string& push_back(const char c)
{
    //判斷容量
    if (_size == _capacity)
    {
        size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2;//防止出現(xiàn)空串的情況
        reserve(newCapacity);
    }
    _arr[_size++] = c;
    return *this;
}
string& append(const char* s)
{
    //判斷容量
    size_t len = strlen(s);
    if (_size + len > _capacity)
    {
        reserve(_size + len);
    }
    strcpy(_arr + _size, s);
    _size += len;
    return *this;
}
string& operator+=(const char c)
{
    push_back(c);
    return *this;
}
string& operator+=(const char* s)
{
    append(s);
    return *this;
}

寫push_back要考慮到原對象為空串的情況(即_capacity為0)。

+=可以復(fù)用push_back和append。

2、insert和earse

string& insert(size_t pos, char c)
{
    assert(pos < _size);
    //判斷容量
    if (_size == _capacity)
    {
        reserve(_capacity + 1);
    }
    //挪動(dòng)數(shù)據(jù)
    for (size_t i = _size; i > pos; --i)
    {
        _arr[i] = _arr[i - 1];
    }
    _arr[pos] = c;
    ++_size;
    return *this;
}
string& insert(size_t pos, const char* s)
{
    size_t len = strlen(s);
    //判斷容量
    if (len + _size > _capacity)
    {
        reserve(len + _size);
    }
    //挪動(dòng)數(shù)據(jù)
    for (size_t i = _size + len; i > pos + len - 1; --i)
    {
        _arr[i] = _arr[i - len];
    }
    memcpy(_arr + pos, s, len);
    _size += len;
    return *this;
}
string& earse(size_t pos, size_t len = npos)
{
    assert(pos < _size);
    //先判斷刪到底的情況
    if (len == npos || pos + len >= _size)
    {
        _arr[pos] = '\0';
        _size = pos;
    }
    else
    {
        memcpy(_arr + pos, _arr + pos + len, _size - pos - len);
        _size -= len;
    }
    return *this;
}

insert接口在挪動(dòng)數(shù)據(jù)時(shí),從最后一個(gè)元素的后一個(gè)(后len個(gè))位置開始覆蓋,可以保證不出現(xiàn)size_t 類型越界的情況。

earse接口,需要分類討論字符串是否刪到底。

注意,這個(gè)pos是const static成員,C++語法中,只有指針和整型的const static成員是可以在類中進(jìn)行初始化的。

3、find

size_t find(const char c, size_t pos = 0)const
{
    assert(pos < _size);
    for (size_t i = pos; i < _size; ++i)
    {
        if (_arr[i] == c)
        {
            return i;
        }
    }
    return npos;
}
size_t find(const char* s, size_t pos = 0)const
{
    assert(pos < _size);
    const char* p = strstr(_arr, s);
    if (p != nullptr)
    {
        return _arr - p;
    }
    return npos;
}

從指定位置找字符或字符串,找到了,返回第一個(gè)匹配字符/子串的下標(biāo)。

七、流插入和流提取

//流插入和流提取的重載時(shí)為了自定義類型的輸入輸出
inline ostream& operator<<(ostream& out, const string& s)//這里訪問的到私有,所以可以不用寫成友元函數(shù)
{
    for (size_t i = 0; i < s.size(); ++i)//流插入按照_size打印,c_str找到'\0'結(jié)束打印
    {                                    //比如我在字符串中間插入一個(gè)'\0',打印結(jié)果不一樣
        out << s[i];
    }
    return out;
}
inline istream& operator>>(istream& in, string& s)
{
    s.clear();//用之前先清空s
    //in >> c;//流提取不會(huì)識(shí)別空格和換行
    char c = in.get();
    char buff[128] = { '\0' };//防止頻繁擴(kuò)容
    size_t i = 0;
    while (c != ' ' && c != '\n')
    {
        if (i == 127)
        {
            s += buff;
            i = 0;
        }
        buff[i++] = c;
        c = in.get();
    }
    if (i > 0)
    {
        buff[i] = '\0';
        s += buff;
    }
    return in;
}

因?yàn)閟tring提供了訪問私有的接口,所以流插入和流提取可以不用重載成string類的友元函數(shù)。

對于流提取,如果頻繁的尾插,會(huì)造成頻繁擴(kuò)容。而且C++的擴(kuò)容和C語言的擴(kuò)容不一樣,C++使用new不能原地?cái)U(kuò)容,只能異地?cái)U(kuò)容,異地?cái)U(kuò)容就會(huì)導(dǎo)致新空間的開辟、數(shù)據(jù)的拷貝、舊空間釋放。為了防止頻繁擴(kuò)容,我們可以創(chuàng)建一個(gè)可以存儲(chǔ)128字節(jié)的數(shù)組,在這個(gè)數(shù)組中操作,這個(gè)數(shù)組滿了就尾插至對象s中。

為什么不能用getline,而是要一個(gè)字符一個(gè)字符尾插呢?因?yàn)榱魈崛∮龅娇崭窈?#39;\n'會(huì)結(jié)束提取,剩余數(shù)據(jù)暫存緩沖區(qū),如果是getline的話,遇到空格是不會(huì)停止讀取的。

八、模擬實(shí)現(xiàn)的string整體代碼

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <assert.h>
using std::cout;
using std::cin;
using std::endl;
using std::ostream;
using std::istream;
namespace jly
{
	class string
	{
	public:
		void swap(string& s)
		{
			std::swap(_arr, s._arr);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}
		//構(gòu)造函數(shù)
		string(const char* s = "")
		{
			_size = strlen(s);//_size和_capacity均不包含'\0'
			_capacity = _size;
			_arr = new char[_size + 1];
			memcpy(_arr, s, _size + 1);
		}
		//拷貝構(gòu)造
		//寫法1
		//string(const string& s)
		//{
		//	_size = s._size;//_size和_capacity均不包含'\0'
		//	_capacity = s._capacity;
		//	_arr = new char[_capacity + 1];
		//	memcpy(_arr, s._arr, _capacity + 1);
		//}
		//寫法2
		string(const string& s)
			:_arr(nullptr)//防止交換后tmp._arr為隨機(jī)值,析構(gòu)出錯(cuò)
		{
			string tmp(s.c_str());//構(gòu)造
			swap(tmp);
		}
		//賦值運(yùn)算符重載
		//寫法1
		//string& operator=(const string& s)
		//{
		//	if (this != &s)//防止自己給自己賦值
		//	{ 
		//		_size = s._size;
		//		_capacity = s._capacity;
		//		char* tmp = new char[_capacity + 1];
		//		delete[] _arr;
		//		_arr = tmp;
		//		memcpy(_arr, s._arr, _capacity + 1);
		//	}
		//	return *this;
		//}
		//寫法2
		string& operator=(const string& s)
		{
			string tmp(s.c_str());//構(gòu)造
			swap(tmp);
			return *this;
		}
		//析構(gòu)函數(shù)
		~string()
		{
			_size = _capacity = 0;
			delete[] _arr;
			_arr = nullptr;
		}
		//string的size()接口
		size_t size()const//右const修飾*this,這樣const和非const對象均可調(diào)用
		{
			return _size;
		}
		//string的c_str()接口
		const char* c_str()const
		{
			return _arr;
		}
		//string的capacity()接口
		size_t capacity()const
		{
			return _capacity;
		}
		//string的clear()接口
		void clear()
		{
			_arr[0] = '\0';
			_size = 0;
		}
		//string的判空
		bool empty()const
		{
			return _size == 0 ? false : true;
		}
		//對operator[]進(jìn)行重載
		char& operator[](size_t pos)//普通對象,可讀可寫
		{
			assert(pos < _size);
			return _arr[pos];
		}
		const char& operator[](size_t pos)const//const對象,僅讀
		{
			assert(pos < _size);
			return _arr[pos];
		}
		//迭代器
		typedef char* iterator;
		iterator begin()const
		{
			return _arr;
		}
		iterator end()const//end指向字符串的'\0'
		{
			return _arr + _size ;
		}
		//string的reserve接口,如果預(yù)開空間小于現(xiàn)有空間,將不會(huì)改變?nèi)萘俊?
		void reserve(size_t n=0)
		{
			if (n + 1 > _capacity)
			{
				char* tmp = new char[n + 1];
				memset(tmp, '\0', n + 1);
				memcpy(tmp, _arr, _size);
				delete[] _arr;
				_arr = tmp;
				_capacity = n;
			}
		}
		//string的resize接口
		void resize(size_t n, char c='\0')
		{
			//判斷n的大小
			if (n > _capacity)
			{
				reserve(n);
				memset(_arr + _size,c,n-_size);
				_size = n;
			}
			else
			{
				_arr[n] = '\0';
				_size = n;
			}
		}
		//插入刪除查找相關(guān)接口
		string& push_back(const char c)
		{
			//判斷容量
			if (_size == _capacity)
			{
				size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2;//防止出現(xiàn)空串的情況
				reserve(newCapacity);
			}
			_arr[_size++] = c;
			return *this;
		}
		string& append(const char* s)
		{
			//判斷容量
			size_t len = strlen(s);
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}
			strcpy(_arr+_size,s);
			_size += len;
			return *this;
		}
		string& operator+=(const char c)
		{
			push_back(c);
			return *this;
		}
		string& operator+=(const char* s)
		{
			append(s);
			return *this;
		}
		string& insert(size_t pos, char c)
		{
			assert(pos < _size);
			//判斷容量
			if (_size == _capacity)
			{
				reserve(_capacity + 1);
			}
			//挪動(dòng)數(shù)據(jù)
			for (size_t i = _size; i > pos; --i)
			{
				_arr[i] = _arr[i - 1];
			}
			_arr[pos] = c;
			++_size;
			return *this;
		}
		string& insert(size_t pos, const char* s)
		{
			size_t len = strlen(s);
			//判斷容量
			if (len + _size > _capacity)
			{
				reserve(len + _size);
			}
			//挪動(dòng)數(shù)據(jù)
			for (size_t i = _size + len; i > pos + len - 1; --i)
			{
				_arr[i] = _arr[i - len];
			}
			memcpy(_arr + pos, s, len);
			_size += len;
			return *this;
		}
		string& earse(size_t pos, size_t len = npos)
		{
			assert(pos<_size);
			//先判斷刪到底的情況
			if (len == npos || pos + len >= _size)
			{
				_arr[pos] = '\0';
				_size = pos;
			}
			else
			{
				memcpy(_arr + pos, _arr + pos + len,_size-pos-len);
				_size -= len;
			}
			return *this;
		}
		size_t find(const char c, size_t pos = 0)const
		{
			assert(pos < _size);
			for (size_t i = pos; i < _size; ++i)
			{
				if (_arr[i] == c)
				{
					return i;
				}
			}
			return npos;
		}
		size_t find(const char* s, size_t pos = 0)const
		{
			assert(pos < _size);
			const char* p = strstr(_arr, s);
			if (p != nullptr)
			{
				return _arr - p;
			}
			return npos;
		}
	private:
		char* _arr;
		size_t _size;
		size_t _capacity;
		const static size_t npos = -1;//只有const static整型、指針成員變量可以在類中定義,其他類型不行
	};
	//流插入和流提取的重載時(shí)為了自定義類型的輸入輸出
	inline ostream& operator<<(ostream& out, const string& s)//這里訪問得到私有,所以可以不用寫成友元函數(shù)
	{
		for (size_t i = 0; i < s.size(); ++i)//流插入按照_size打印,c_str找到'\0'結(jié)束打印
		{                                    //比如我在字符串中間插入一個(gè)'\0',打印結(jié)果不一樣
			out << s[i];
		}
		return out;
	}
	inline istream& operator>>(istream& in, string& s)
	{
		s.clear();//用之前先清空s
		//in >> c;//流提取不會(huì)識(shí)別空格和換行
		char c=in.get();
		char buff[128] = { '\0' };//防止頻繁擴(kuò)容
		size_t i = 0;
		while (c != ' ' && c != '\n')
		{
			if (i == 127)
			{
				s += buff;
				i = 0;
			}
			buff[i++] = c;
			c = in.get();
		}
		if (i > 0)
		{
			buff[i] = '\0';
			s += buff;
		}
		return in;
	}
	//測試函數(shù)
	void test1()
	{
	
	}
}

以上就是C++模擬實(shí)現(xiàn)string的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于C++實(shí)現(xiàn)string的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • c語言輸出字符串中最大對稱子串長度的3種解決方案

    c語言輸出字符串中最大對稱子串長度的3種解決方案

    這篇文章主要介紹了c語言輸出字符串中最大對稱子串長度的3種解決方案,需要的朋友可以參考下
    2014-03-03
  • C++私有繼承(一)

    C++私有繼承(一)

    這篇文章主要介紹了C++私有繼承,在私有繼承當(dāng)中,基類的公有成員和保護(hù)成員都會(huì)成為派生類的私有成員。這意味著基類的方法都會(huì)被private關(guān)鍵字描述,我們可以在派生類中使用它,但類對象無法直接調(diào)用,下面來看看詳細(xì)內(nèi)容吧
    2022-01-01
  • Visual Studio調(diào)試C/C++教程指南

    Visual Studio調(diào)試C/C++教程指南

    VisualStudio是微軟開發(fā)的一款集成開發(fā)環(huán)境軟件,本文主要介紹了Visual Studio調(diào)試C/C++教程指南,熟悉地掌握基于VS的C/C++調(diào)試技術(shù),可以大幅提升調(diào)試性能,感興趣的可以了解一下
    2024-06-06
  • C/C++ Qt 自定義Dialog對話框組件應(yīng)用案例詳解

    C/C++ Qt 自定義Dialog對話框組件應(yīng)用案例詳解

    有時(shí)候我們需要一次性修改多個(gè)數(shù)據(jù),使用默認(rèn)的模態(tài)對話框似乎不太夠用,此時(shí)我們需要自己創(chuàng)建一個(gè)自定義對話框。這篇文章主要介紹了Qt自定義Dialog對話框組件的應(yīng)用,感興趣的同學(xué)可以學(xué)習(xí)一下
    2021-11-11
  • C/C++中一次性執(zhí)行多個(gè)DOS命令的實(shí)現(xiàn)思路

    C/C++中一次性執(zhí)行多個(gè)DOS命令的實(shí)現(xiàn)思路

    在C語言中執(zhí)行DOS命令的方法很多,在這就不一給大家一一介紹了,本文重點(diǎn)給大家介紹C/C++中一次性執(zhí)行多個(gè)DOS命令的實(shí)現(xiàn)思路,需要的朋友參考下
    2017-12-12
  • c++ STL常用遍歷算法

    c++ STL常用遍歷算法

    這篇文章主要介紹了c++ STL常用遍歷算法的實(shí)現(xiàn),幫助大家更好的理解和使用c++,感興趣的朋友可以了解下
    2020-12-12
  • C++多繼承多態(tài)的實(shí)例詳解

    C++多繼承多態(tài)的實(shí)例詳解

    這篇文章主要介紹了C++多繼承多態(tài)的實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • C++ Boost Random隨機(jī)函數(shù)詳解

    C++ Boost Random隨機(jī)函數(shù)詳解

    Boost是為C++語言標(biāo)準(zhǔn)庫提供擴(kuò)展的一些C++程序庫的總稱。Boost庫是一個(gè)可移植、提供源代碼的C++庫,作為標(biāo)準(zhǔn)庫的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開發(fā)引擎之一,是為C++語言標(biāo)準(zhǔn)庫提供擴(kuò)展的一些C++程序庫的總稱
    2022-11-11
  • C語言實(shí)現(xiàn)推箱子功能匯總

    C語言實(shí)現(xiàn)推箱子功能匯總

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)推箱子功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • C語言文件操作與相關(guān)函數(shù)介紹

    C語言文件操作與相關(guān)函數(shù)介紹

    文件(file)一般指存儲(chǔ)在外部介質(zhì)上數(shù)據(jù)的集合,比如我們經(jīng)常使用的.txt, .bmp, jpg. .exe,.rmvb等等,下面這篇文章主要給大家介紹了關(guān)于C語言文件操作的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-09-09

最新評(píng)論