string类是C++的一个常见的面试题,考查面试者的基本功,虽然简单,但是有很多细节需要注意。
#pragma once #include <assert.h> /* 深拷贝与浅拷贝: 浅拷贝,只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,深拷贝不但对指针进行拷贝, 而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针。浅拷贝是指源对象 与拷贝对象共用一份实体,仅仅是引用的变量不同(名称不同)。对其中任何一个对象的改动都会影响另外一个对象。 深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。 举个例子,一个人名叫张三,后来用他克隆(假设法律允许)了另外一个人,叫李四,不管是张三缺胳膊少腿 还是李四缺胳膊少腿都不会影响另外一个人。 */ class String { friend ostream& operator<<(ostream& _cout, const String& s); public: /* String() :_pStr(/ *new char(‘\0‘)* /new char[1]) { _pStr[0] = ‘\0‘; //不能是"\0" } //new和delete,new[]和delete[]一定要匹配使用 //strlen 不能传NULL String(char* pStr) :_pStr(new char[strlen(pStr)+1]) { strcpy(_pStr, pStr); //strcpy会拷贝‘\0‘过去 } */ //构造函数合并 String(char* pStr = "") { _size = strlen(pStr); _capacity = _size+1; _pStr = new char[_size+1]; strcpy(_pStr, pStr); } /* //拷贝构造函数常规写法 String(const String& s) :_pStr(new char[strlen(s._pStr)+1]) { strcpy(_pStr, s._pStr); } */ String(const String& s) :_pStr(NULL) //需要先将this->_pStr置为空,否则交换后tmp为随机值,析构tmp时delete[]出现错误 { String tmp(s._pStr); std::swap(_pStr, tmp._pStr); } /* //赋值运算符重载常规写法 -> 释放原来的空间,开辟和s一样大的空间 String& operator=(const String& s) { if (this != &s) { / * //存在一致性问题。如果new空间失败,原来的空间将被释放,深拷贝失败 delete[] _pStr; _str = new char[strlen(s._pStr)+1]; strcpy(_pStr, s._pStr); * / //先开辟空间,再拷贝 char* tmp = new char[strlen(s._pStr)+1]; strcpy(tmp, s._pStr); delete[] _pStr; _pStr = tmp; } return *this; } */ /* //赋值运算符重载现代写法 String& operator=(const String& s) { if (this != &s) { String tmp(s._pStr); std::swap(_pStr, tmp._pStr); } return *this; } */ //赋值运算符重载现代写法 String& operator=(String s) { swap(_pStr, s._pStr); return *this; } ~String() { if (_pStr) delete[] _pStr; } char* C_Str() { return _pStr; } char& operator[](size_t index) { return _pStr[index]; } void PushBack(const char& ch) { /*_CheckCapacity(_size + 2); _pStr[_size] = ch; _pStr[++_size] = ‘\0‘;*/ Insert(_size, ch); } void PopBack() { assert(_size > 0); --_size; _pStr[_size] = ‘\0‘; } void Insert(size_t pos, char ch) { assert(pos <= _size); _CheckCapacity(_size + 2); size_t cur = _size; while (cur >= pos) { _pStr[cur+1] = _pStr[cur]; cur--; } _pStr[pos] = ch; ++_size; } void Insert(int pos, const char* str) { assert(pos>=0 && pos <= _size); //增容 size_t size = strlen(str); _CheckCapacity(_size+1+size); //挪动数据 int index = _size; while (index >= pos) { _pStr[index+size] = _pStr[index]; --index; } //拷贝 for (size_t i = 0; i < size; ++i) { _pStr[pos++] = str[i]; } _size += size; } int Find(char ch) { for (size_t index = 0; index < _size; ++index) { if (_pStr[index] = ch) { return index; } } return -1; } int Find(const char* subStr) { assert(subStr); size_t dstIndex = 0; //要查找的子串 size_t srcIndex = 0; size_t subSize = strlen(subStr); for (dstIndex = 0; dstIndex <= _size - subSize; ++dstIndex) { for (srcIndex = 0; srcIndex < subSize; ++srcIndex) { if (subStr[srcIndex] != _pStr[dstIndex+srcIndex]) { break; } } if (srcIndex == subSize) { return dstIndex; } } return -1; } void Erase(size_t pos) { assert(pos < _size); for (size_t i = pos+1; i <= _size; ++i) { _pStr[i-1] = _pStr[i]; } --_size; } String& operator+=(const String& s) { Insert(_size, s._pStr); return *this; } //String s("Hello"); //可以使用 s += String(" World"); String(" World") -> 拷贝构造 -> String& s //也可使用 s += " World"; " World" -> 构造函数 -> String& s //如果改为String& operator+=(String& s)则不能使用 s += " World"。 例如: /* int i = 0; //double& a = i; //i先创建一个临时对象,然后把临时对象给double& a,a就成为一个临时变量的引用。错误 const double& a = i; //加const,可以引用临时变量。正确 */ /* String s1 = "sssssss"; //"sssssss"生成一个匿名对象,匿名对象再构造s1。编译器将两步优化为一步:"sssssss"直接构造s1。 //String& s2 = "sssssss"; //不能引用匿名(临时)对象。错误 const String& s3 = "sssssss"; //加const,可以引用临时变量。正确 */ bool operator==(const String& s) { return (strcmp(_pStr, s._pStr) == 0); } bool operator>(const String& s) { return (strcmp(_pStr, s._pStr) > 0); } bool operator>=(const String& s) { return (*this > s || *this == s); } bool operator<(const String& s) { return !(*this >= s); } bool operator<=(const String& s) { return !(*this > s); } protected: void _CheckCapacity(size_t needSize) { if (_size+1 >= _capacity) { _capacity = _capacity+needSize > 2*_capacity ? needSize : 2*_capacity; _pStr = (char*)realloc(_pStr, _capacity); } } protected: char* _pStr; size_t _size; size_t _capacity; }; ostream& operator<<(ostream& _cout, const String& s) { _cout<<s._pStr; return _cout; }
推荐一篇写的很好的文章:
C++面试中string类的一种正确写法:http://coolshell.cn/articles/10478.html
本文出自 “zgw285763054” 博客,请务必保留此出处http://zgw285763054.blog.51cto.com/11591804/1839293
原文地址:http://zgw285763054.blog.51cto.com/11591804/1839293