栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

C++ string类(包括深浅拷贝)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++ string类(包括深浅拷贝)

目录

一.字符码表

一.为什么用string类

二.使用标准库中的string类

1.string类

2.string中的常用接口说明

(1)string类对象的常见构造

(2)string类对象访问及遍历操作

(3)string类对象遍历方式

(4)string类对象的容量操作

(5)string类对象的修改操作

(6)string类非成员函数

三.浅拷贝与深拷贝

1.浅拷贝

2.深拷贝

四.string类的分部模拟实现(包括传统写法和现代写法)

1.私有成员

2.构造函数

3.拷贝构造函数

(1)传统写法

(2)现代写法

4.赋值运算符重载

(1)传统写法

(2)现代写法

5.析构函数

6.下标[]运算符重载

7.有效字符个数和存储空间容量

8.reserve函数

9.resize函数

10.尾插字符push_back函数

11.尾插字符串append函数

12.+=运算符重载

13.插入函数

14.删除函数

15.查找函数

16.清除函数

17.C语言形式返回字符串

18.迭代器

19.>、<、==等运算符重载

20.流插入、流提取运算符重载

五.string类模拟实现总代码


前言:从这里开始就正式进入STL了,STL对与C++是很重要的,接下来将会把STL的重要容器都学习一遍,并且也会包括STL的其它部分。 

一.字符码表

        我们都知道ASCII码表,但是ASCII码表只有符号和英文字母,并没有中文汉字,或是其它语言的字符,因此就又有了其它的码表。

        例如:unicode(全世界语言) utf-8 utf-16 utf-32 gbk(国标)

除此之外呢, 在我们搜索string时,会发现string有如下4个实例化,而这4个实例化的作用就是为了支持多种字符

一.为什么用string类

        C语言中,字符串时以''结尾的 一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,容易导致越界访问。

        因此有了string类的出现。

        在OJ题中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便。快捷。基本都使用string类,很少有人去使用C库中的字符串操作函数。

二.使用标准库中的string类

1.string类

①string是表示字符串的字符串类

②该类的接口与常规容器的接口基本相同,但添加了一些专门用来操作string的常规操作

③string在底层实际是:basic_string模板类的别名,typedef basic_string string;

④不能操作多字节或者变长字符的序列。

在使用string类时,必须包含#include 头文件。

2.string中的常用接口说明

(1)string类对象的常见构造

①string()        构造空的string类对象,即空字符串

②string(const char* s)        用C格式的string来构造string类对象

③string(size_t n, char c)        string类对象中包含n个字符c

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

int main()
{
	string s1; // 构造空的string类对象
	string s2("hello world"); // 用C格式的字符串构造

	string s3(s2); // 拷贝构造
	string s4 = s2; // 拷贝构造

	string s5("http://m.cplusplus.com/reference/string/string/string/", 4); // 用前4个字符构造
	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	cout << s4 << endl;
	cout << s5 << endl;

    return 0;
}

(2)string类对象访问及遍历操作

①operator[]        返回pos位置的字符,const string类对象调用

②iterator(begin + end )       begin获取一个字符的迭代器 +end获取最后一个字符下一个位置的迭代器

③reverse_iterator(rbegin + rend)       begin获取一个字符的迭代器 +end获取最后字符的下一个位置的迭代器

④范围for        C++11支持更简洁的范围for的新遍历方式    

(3)string类对象遍历方式

①下标+[]

for (size_t i = 0; i < s1.size(); i++)
{
		cout << s1[i] << " ";
}

有一个与[]类似的at,使用方法相同,但有一点差别 

s1.at(6); // 使用at看第6个元素
s1[6] // 使用[]看第6个元素

用[]失败了报断言错误,直接结束程序。

而at相对温和,失败会抛异常。

但是一般都是用operator[],几乎不会使用at。

②迭代器

迭代器一共4种:iterator、reverse_iterator、const_iterator、const_reverse_iterator

正向迭代器: 

string s("hello world");
string::iterator it = s.begin();
while (it != s.end())
{
	(*it) += 1;
	cout << *it << " ";
	++it;
}

反向迭代器: 

string::reverse_iterator rit = s.rbegin();
while (rit != s.rend())
{
	(*rit) += 1;
	cout << *rit << " ";
	++rit;
}

 这里我们可以发现正向迭代器和反向迭代器都可以对string类对象内部字符进行修改,因此迭代器还有两种:const_iterator和const_reverse_iterator,这两种迭代器都只能遍历,而不能修改

string::const_iterator it = rs.begin();
while (it != rs.end())
{
	/

	for (auto ch : s)
	{
		out << ch;
	}

	return out;
}

流提取:

第一种:

        这里我们用ch = in.get()是为了在输入时,可以识别出 空格' ' 和 回车'n' ,否则将无法结束输入。

istream& operator>>(istream& in, string& s)
{
    char ch;
    // 不能写成这种形式
	//in >> ch;

	ch = in.get();.
	while (ch != ' ' && ch != 'n')
	{
		s += ch;
		in >> ch;
	}

	return in;
}

第二种:

        这里的buff数组以及while循环是为了提高效率的。

        我们不知道输入的字符串是长还是短,当字符串比较短时,那么上面第一种方法是可以的。而当字符串很长时,每当输入一个字符就+=一次,会导致效率较低,因此这里是每满128个字符时,进行一次+=,可以提升一定的效率。

istream& operator>>(istream& in, string& s)
{
	char ch;
	ch = in.get();
	char buff[128] = { '' };
	size_t i = 0;
	while (ch != ' ' && ch != 'n')
	{
		buff[i++] = ch;
		if (i == 127)
		{
			s += buff;
			memset(buff, '', 128);
			i = 0;
		}

		ch = in.get();
	}

	s += buff;
	return in;
}

五.string类模拟实现总代码
#pragma once

#include 

namespace hb
{
	class string
	{
	public:
		typedef char* iterator;
		typedef const char* const_iterator;

		const_iterator begin() const
		{
			return _str;
		}

		const_iterator end() const
		{
			return _str + _size;
		}

		iterator begin()
		{
			return _str;
		}

		iterator end()
		{
			return _str + _size;
		}

		string(const char* str = "")
			: _size(strlen(str))
			, _capacity(_size)
		{
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}

		// 传统写法:
		

		void swap(string& s)
		{
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}

		// 现代写法:
		string(const string& s)
			: _str(nullptr)
			, _size(0)
			, _capacity(0)
		{
			string tmp(s._str);
			swap(tmp);
		}

		// 1.
		

		// 2.
		string operator=(string s)
		{
			swap(s);
			return *this;
		}

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

		const char* c_str() const
		{
			return _str;
		}

		char& operator[](size_t pos)
		{
			assert(pos < _size);

			return _str[pos];
		}

		const char& operator[](size_t pos) const
		{
			assert(pos < _size);

			return _str[pos];
		}

		size_t size() const
		{
			return _size;
		}

		size_t capacity() const
		{
			return capacity();
		}

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

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

		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 = '')
		{
			if (n < _size)
			{
				_size = n;
				_str[_size] = '';
			}
			else
			{
				if (n > _capacity)
				{
					reserve(n);
				}

				for (size_t i = _size; i < n; ++i)
				{
					_str[i] = ch;
				}
				_size = n;
				_str[_size] = '';
			}
		}

		void push_back(char ch)
		{
			

			insert(_size, ch);
		}

		void append(const char* str)
		{
			

			insert(_size, str);
		}

		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 - 1)
			{
				_str[end] = _str[end - len];
				--end;
			}

			strncpy(_str + pos, str, len);
			_size += len;

			return *this;
		}

		void earse(size_t pos, size_t len = npos)
		{
			assert(pos < _size);

			if (len == npos || pos + len >= _size)
			{
				_str[pos] = '';
				_size = pos;
			}
			else
			{
				size_t begin = pos + len;
				while (begin <= _size)
				{
					_str[begin - len] = _str[begin];
					++begin;
				}

				_size -= len;
			}
		}

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

			return npos;
		}

		size_t find(const char* str, size_t pos = 0)
		{
			const char* p = strstr(_str + pos, str);
			if (p == nullptr)
			{
				return npos;
			}
			else
			{
				return p - _str;
			}
		}

		void clear()
		{
			_str[0] = '';
			_size = 0;
		}

	private:
		char* _str;
		size_t _size;	 // 有效字符个数
		size_t _capacity; // 实际存储有效字符的空间

		const static size_t npos;
	};

	const size_t string::npos = -1;

	ostream& operator<<(ostream& out, const string& s)
	{
		
		for (auto ch : s)
		{
			out << ch;
		}

		return out;
	}

	istream& operator>>(istream& in, string& s)
	{
		//char ch;
		in >> ch;
		//ch = in.get();.
		//while (ch != ' ' && ch != 'n')
		//{
		//	s += ch;
		//	in >> ch;
		//}

		//return in;

		char ch;
		ch = in.get();
		char buff[128] = { '' };
		size_t i = 0;
		while (ch != ' ' && ch != 'n')
		{
			buff[i++] = ch;
			if (i == 127)
			{
				s += buff;
				memset(buff, '', 128);
				i = 0;
			}

			ch = in.get();
		}

		s += buff;
		return in;
	}

	bool operator<(const string& s1, const string& s2)
	{
		return strcmp(s1.c_str(), s2.c_str()) < 0;
	}

	bool operator==(const string& s1, const string& s2)
	{
		return strcmp(s1.c_str(), s2.c_str()) == 0;
	}

	bool operator<=(const string& s1, const string& s2)
	{
		return s1 < s2 || s1 == s2;
	}

	bool operator>(const string& s1, const string& s2)
	{
		return !(s1 <= s2);
	}

	bool operator>=(const string& s1, const string& s2)
	{
		return !(s1 < s2);
	}

	bool operator!=(const string& s1, const string& s2)
	{
		return !(s1 == s2);
	}
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1005656.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号