参考《数据结构——C++实现(第二版)》科学出版社P119
花了两天的时间大致完整地实现了一遍String。
自己暂时还没有发现错误,如有错误或可以优化改进的地方,欢迎指出!
提醒我自己要注意几个点:
- 运算符返回引用还是对象?
- 字符串后面系统会自动加上’\0’作为结束标志
String类还有许多可以改进的地方,比如说运用引用计数
、写时拷贝
等技术提高效率。
如果希望区分operator[]的读和写两种动作。可以运用缓式评估
思想,利用proxy class
来区分其左值运用和右值运用。
以上这些技术详见《More Effective C++》。
class String {
private:
char *pval;
size_t length;
public:
String() : pval(nullptr), length(0) {}
String(const String& s);
String(const char* s);
String& operator=(const String& s);
virtual ~String() { delete [] pval; }
bool isEmpty() const { return length == 0; }
size_t getLength() const { return length; }
void swap(String& s); //交换两个字符串的内容
const char* cStr() const;
bool insert(const String& s, size_t i); //在位置i之后插入s
bool erase(size_t p, size_t n); //删除位置从p开始的后面n个字符(p的取值为0到length-1)
String operator+(const String& s);
String& operator+=(const String& s);
String& operator+=(const char* s);
bool operator==(const String& s) const;
bool operator!=(const String& s) const;
char& operator[](size_t i) const;
friend ostream& operator<<(ostream& os, String& s);
};
String::String(const String& s) {
length = strlen(s.pval);
pval = new char[length + 1];
strcpy(pval, s.cStr());
}
String::String(const char* s) {
length = strlen(s);
pval = new char[length + 1];
strcpy(pval, s);
pval[length] = '\0';
}
String& String::operator=(const String& s) {
if (&s != this) {
delete [] pval;
length = strlen(s.cStr());
pval = new char[length + 1];
strcpy(pval, s.cStr());
}
return *this;
}
const char* String::cStr() const {
return static_cast<const char*>(pval);
}
bool String::insert(const String& s, size_t i) {
const char* p = s.cStr();
if (i < 0 || i >= length) {
return false;
}
size_t len = length + s.length; //总长度
length = len;
char *temp = new char[len + 1]; //临时存放拼接的字符串
strncpy(temp, pval, i); //将pval指向的字符串复制给temp,最多复制i个
temp[i] = '\0';
strcat(temp, p); //将pval前半部分和s拼接起来
size_t j = i + s.length; //
for (size_t k = i; k < length; ++k, ++j) {
temp[j] = pval[k];
}
temp[len] = '\0';
pval = temp;
return true;
}
bool String::erase(size_t p, size_t n) {
if (p < 0 || (p + n) > length) {
return false;
}
size_t len = length - n;
char *temp = new char[length + 1];
strcpy(temp, pval);
delete [] pval;
pval = new char[len + 1];
strncpy(pval, temp, p + 1);
for (size_t i = p + n; i < length; ++i) {
pval[i - n] = temp[i];
}
delete [] temp;
length -= n;
return true;
}
String String::operator+(const String& s) {
const char *cs = s.cStr();
String str;
length = length + s.length;
str.pval = new char[length + 1];
strcpy(str.pval, pval);
strcat(str.pval, s.cStr());
return str;
}
String& String::operator+=(const String& s) {
char *temp = new char[length + 1];
strcpy(temp, pval);
delete [] pval;
length += s.length;
pval = new char[length + 1];
strcpy(pval, temp);
strcat(pval, s.pval);
delete [] temp;
return *this;
}
String& String::operator+=(const char* s) {
size_t len = 0;
const char* t = s;
while(*t != '\0') {
++len;
++t;
}
char *temp = new char[length + 1];
strcpy(temp, pval);
delete [] pval;
length += len;
pval = new char[length + 1];
strcpy(pval, temp);
strcat(pval, s);
return *this;
}
bool String::operator==(const String& s) const {
return strcmp(this->cStr(), s.cStr()) == 0;
}
bool String::operator!=(const String& s) const {
return strcmp(this->cStr(), s.cStr()) != 0;
}
//为了效率,operator[]不用考虑越界处理
char& String::operator[](size_t i) const {
return pval[i];
}
//最好不要定义在类内,否则cout要写在<<右边
ostream& operator<<(ostream& os, String& s) {
os << s.pval;
return os;
}
void String::swap(String& s) {
using std::swap;
swap(this->pval, s.pval);
swap(this->length, s.length);
}
void swap(String& lhs, String& rhs) {
lhs.swap(rhs);
}