【C++】第十节—string类(完结篇)——详解+代码示例

2025-04-27 0 946

hello ,好久不见!

云边有个稻草人-个人主页

C++优质专栏!~欢迎订阅~

目录

一、string实现时要注意的细节点

1.void string::Insert(size_t pos, char ch)

2.void string::Insert(size_t pos, const char* str)

第一种方法

第二种方法

3.到底在哪里定义static const size_t npos ?

4.实现取域名

5.拷贝—拷贝构造和赋值

6.流插入

7.三个swap

二、

2.1 经典的string类问题

2.2 浅拷贝

2.3 深拷贝

(1)【传统版写法的String类】

(2)【现代版写法的String类】

(3)【写时拷贝】(了解)

(4)扩展阅读

(5)编码

三、综合代码

string.h

string.cpp

test.cpp


正文开始——

一、string实现时要注意的细节点

1.void string::Insert(size_t pos, char ch)

【C++】第十节—string类(完结篇)——详解+代码示例

void string::Insert(size_t pos, char ch)
{
	//对于任何的插入操作都要先判断空间是否充足提前预留足够的空间
	if (_size == _capacity)
	{
		reserve(_capacity == 0 ? 4 : 2 * _capacity);
	}
	size_t end = _size+1;
	//预留出pos位置的空间进行插入操作
	while (end > pos)
	{
		_str[end] = _str[end - 1];
		--end;
	}
	_str[pos] = ch;
	_size++;
}

2.void string::Insert(size_t pos, const char* str)

第一种方法

跟我们前面讲的很相似,利用强转来解决类型的问题

void string::Insert(size_t pos, const char* str)
{
	//还是先扩容
	size_t len = strlen(str);
	if (_size + len > _capacity)
	{
		//扩容
		size_t newCapacity = 2 * _capacity;
		//扩2倍不够直接需要多少扩多少
		if (newCapacity < _size + len)
			newCapacity = _size + len;
		reserve(newCapacity);
	}

	int end = _size;
	while (end >= (int)pos)
	{
		_str[end + len] = _str[end];
		end--;
	}
	
	//将str进行挨个插入
	for (size_t i = 0; i < len; i++)
	{
		_str[pos + i] = str[i];
	}
	_size += len;
}
第二种方法

是将end-len移到end指向的数据

【C++】第十节—string类(完结篇)——详解+代码示例

void string::Insert(size_t pos, const char* str)
{
	//还是先扩容
	size_t len = strlen(str);
	if (_size + len > _capacity)
	{
		//扩容
		size_t newCapacity = 2 * _capacity;
		//扩2倍不够直接需要多少扩多少
		if (newCapacity < _size + len)
			newCapacity = _size + len;
		reserve(newCapacity);
	}

	size_t end = _size + len;
	while (end >= pos+len)   //end-len==pos,end==pos+len,
	{
		_str[end] = _str[end-len];
		end--;
	}

	//将str进行挨个插入
	for (size_t i = 0; i < len; i++)
	{
		_str[pos + i] = str[i];
	}
	_size += len;
}

3.到底在哪里定义static const size_t npos ?

(1)所有的.c或者.cpp文件在编译链接的时候都会生成.o文件(VS下叫.obj文件),.h文件在预处理的时候就在两个.cpp文件里面展开了,我们在类域外面定义的npos就会在两个.cpp里面展开,当两个.cpp文件链接合并生成可执行程序的时候,就构成了下面报错里面的重定义,所以当静态成员变量定义和声明分离的时候要在.cpp文件里面定义,不能像以前那样在类里面声明在类外面定义。对于npos要加上const,不可修改。(2)同时npos要在定义的时候给值,对于const对象是只有定义时一次初始化的机会。(3)特殊的一点,对于静态的const(只有整型类型的数据才可以的,这算是一个特殊处理)成员变量可以在声明的时候给缺省值,那么在定义的时候就不可以再给值了。

【C++】第十节—string类(完结篇)——详解+代码示例

【C++】第十节—string类(完结篇)——详解+代码示例

总结一下,对于这种情况有两种解决办法

【C++】第十节—string类(完结篇)——详解+代码示例

【C++】第十节—string类(完结篇)——详解+代码示例

【C++】第十节—string类(完结篇)——详解+代码示例

4.实现取域名

【C++】第十节—string类(完结篇)——详解+代码示例

//取域名
void test_string4()
{
	lrq::string s1 = "https://mpbeta.csdn.net/mp_blog/creation/editor/147116669?spm=1000.2115.3001.4503";
	size_t pos1 = s1.find(':');
	size_t pos2 = s1.find('/', pos1 + 3);

	//判断是否找到目标字符
	if (pos1 != string::npos && pos2 != string::npos)//npos受类域影响
	{
		lrq::string domain = s1.substr(pos1 + 3, pos2 - (pos1 + 3));//注意pos1和pos2到底指向哪些个位置
		cout << domain.c_str() << endl;
	}
}

5.拷贝—拷贝构造和赋值

【C++】第十节—string类(完结篇)——详解+代码示例

我们不显示写拷贝构造和赋值拷贝(都是一种赋值行为),编译器默认都会进行浅拷贝。(1)像上面的代码将s1拷贝赋值给s2,编译器默认的浅拷贝会导致s2和s1指向同一块空间,函数结束的时候会先析构s2再析构s1导致同一块空间析构两次就会出现上面的运行崩溃;(2)还会导致内存泄漏,s2之前的空间没有得到释放。(如果一个类需要显示写析构,那么一般就需要写拷贝构造和赋值)

【C++】第十节—string类(完结篇)——详解+代码示例

//s1 = s3
string& string::operator=(const string& s)
{
	if (this != &s)
	{
		//上来先将s1给释放掉
		delete[] _str;
		_str = new char[s._capacity + 1];//预留一个\\0的空间
		strcpy(_str, s._str);
		_size = s._size;
		_capacity = s._capacity;
	}
	return *this;
}

6.流插入

我们输入的是abcd efg,中间包含一个空格字符,但是ch好像并没有从缓冲区里面提取到空格,看下图,记住,cin在直接使用流提取的时候无论输入任何类型,int,char,它都会默认忽略掉空格和换行,规定认为空格和换行都是多个值之间的分割,也就无法判断什么时候结束,所以我们要进行代码的修改。

【C++】第十节—string类(完结篇)——详解+代码示例

我们使用istream类里面的get,可以提取到空格和换行

【C++】第十节—string类(完结篇)——详解+代码示例

【C++】第十节—string类(完结篇)——详解+代码示例

//cin>>str,这个实现的功能和前面讲的getline很像,只不过结束字符不同而已,我们要融会贯通一下
istream& operator>>(istream& is, string& str)
{
	str.clear();//清空str里面原来的字符,否则会继续加在str上面,这是实现和STL里面的string::>>一样的效果

	char ch;
	ch = is.get();
	while (ch != ' ' && ch != '\\n')
	{
		str += ch;
		ch = is.get();
	}

	return is;
}

优化一下: 

istream& operator>>(istream& is, string& str)
	{
		str.clear();

		int i = 0;
		char buff[256];

		char ch;
		ch = is.get();
		while (ch != ' ' && ch != '\\n')
		{
			// 放到buff
			buff[i++] = ch;
			if (i == 255)
			{
				buff[i] = '\\0';
				str += buff;
				i = 0;
			}

			ch = is.get();
		}

		if (i > 0)
		{
			buff[i] = '\\0';
			str += buff;
		}

		return is;
	}

7.三个swap

【C++】第十节—string类(完结篇)——详解+代码示例

二、

2.1 经典的string类问题

上面已经对
string
类进行了简单的介绍,大家只要能够正常使用即可。在面试中,面试官总喜欢让学生自己来模拟实现string
类,最主要是实现
string
类的构造、拷贝构造、赋值运算符重载以及析构函数。大家看下以下string
类的实现是否有问题?

平台声明:以上文章转载于《CSDN》,文章全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,仅作参考。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/lrq13965748542/article/details/147116669

遇见资源网 编程语言 【C++】第十节—string类(完结篇)——详解+代码示例 http://www.ox520.com/157400.html

常见问题

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务