C++实现string类
string类相比于char*的字符串,在使用中不必担心内存是否足够、字符串长度等等。作为一个类出现,它集成的操作函数足以完成我们大多数情况下的需要。我们可以用 = 进行赋值操作,== 进行比较,+ 做串联等。
C++提供的string类基本满足开发需要,而自己实现string类多在面试题中出现。限于时间,不可能要求具备 std::string 的功能,但至少要求能正确管理资源。
函数声明 | 函数功能 |
---|---|
String(const char *str = nullptr); | 构造函数 |
String(const String &that); | 拷贝构造函数 |
~String(void); | 析构函数 |
String &operator=(const String &that); | 赋值运算符 |
String operator+(const String &that) const; | 字符串连接 |
bool operator==(const String &that) const; | 判断相等 |
char operator[](int index) const; | 数组索引 |
int length(void) const; | 返回字符串长度 |
char *c_str(void) const; | 返回C风格的字符串 |
String &exchange(void); | 字符串逆序 |
friend ostream &operator<<(ostream &os, const String &that); | 标准输出 |
friend istream &operator>>(istream &is, String &that); | 标准输入 |
构造函数和析构函数
代码如下
String::String(const char *pstr)
{
m_pstr = new char[strlen(pstr?pstr:"") + 1];
strcpy(m_pstr, pstr?pstr:"");
}
String::String(const String &that)
{
m_pstr = new char[strlen(that.m_pstr) + 1];
strcpy(m_pstr, that.m_pstr);
}
String::~String(void)
{
if (m_pstr) {
delete[] m_pstr;
m_pstr = nullptr;
}
}
自己实现的String类只维护char *m_pstr一个成员参数,构造函数类内声明有默认参数nullptr,使用三目运算符(? : )判断。构造函数里调用new [],析构函数里必须调用delete []。释放内存后须将m_pstr指向空。
重载函数
代码如下
String &String::operator=(const String &that)
{
if (&that != this) {
delete[] m_pstr;
m_pstr = new char[strlen(that.m_pstr) + 1];
strcpy(m_pstr, that.m_pstr);
}
return *this;
}
String String::operator+(const String &that) const
{
String newString;
if (!that.m_pstr) {
newString = *this;
} else if (!this->m_pstr) {
newString = that;
} else {
newString.m_pstr = new char[strlen(this->m_pstr) +
strlen(that.m_pstr) + 1];
strcpy(newString.m_pstr, this->m_pstr);
strcat(newString.m_pstr, that.m_pstr);
}
return newString;
}
bool String::operator==(const String &that) const
{
if (strlen(this->m_pstr) != strlen(that.m_pstr)) {
return false;
} else {
return strcmp(this->m_pstr, that.m_pstr)?false:true;
}
}
char String::operator[](int index) const
{
if (index > 0 && index < strlen(this->m_pstr)) {
return this->m_pstr[index];
} else {
return '\0';
}
}
ostream &operator<<(ostream &os, const String &that)
{
os << that.m_pstr;
return os;
}
istream &operator>>(istream &is, String &that)
{
is >> that.m_pstr;
return is;
}
重载 = 运算符时须注意深、浅拷贝问题。在申请新的内存之前必须释放旧内存,防止内存泄漏。重载 + 运算符时判断其中一个字符串是否为空,增加代码运行效率。重载 [] 运算符时要注意不能访问越界。
功能函数
代码如下
int String::length(void) const
{
return strlen(this->m_pstr);
}
char *String::c_str(void) const
{
return this->m_pstr;
}
String &String::exchange(void)
{
for (int i = 0; i < strlen(m_pstr) / 2; i++) {
m_pstr[i] ^= m_pstr[strlen(m_pstr) - i - 1];
m_pstr[strlen(m_pstr) - i - 1] ^= m_pstr[i];
m_pstr[i] ^= m_pstr[strlen(m_pstr) - i - 1];
}
return *this;
}
功能函数大体是对C风格的函数进行封装,方法、种类很多,这里不做过多介绍。
完整源代码
string.h
#ifndef __STRING_H
#define __STRING_H
#include <iostream>
using namespace std;
class String {
friend ostream &operator<<(ostream &os, const String &that);
friend istream &operator>>(istream &is, String &that);
public:
String(const char *str = nullptr);
String(const String &that);
~String(void);
String &operator=(const String &that);
String operator+(const String &that) const;
bool operator==(const String &that) const;
char operator[](int index) const;
int length(void) const;
char *c_str(void) const;
String &exchange(void);
private:
char *m_pstr;
};
#endif /* __STRING_H */
string.c
#include <cstring>
#include "string.h"
String::String(const char *pstr)
{
m_pstr = new char[strlen(pstr?pstr:"") + 1];
strcpy(m_pstr, pstr?pstr:"");
}
String::String(const String &that)
{
m_pstr = new char[strlen(that.m_pstr) + 1];
strcpy(m_pstr, that.m_pstr);
}
String::~String(void)
{
if (m_pstr) {
delete[] m_pstr;
m_pstr = nullptr;
}
}
String &String::operator=(const String &that)
{
if (&that != this) {
delete[] m_pstr;
m_pstr = new char[strlen(that.m_pstr) + 1];
strcpy(m_pstr, that.m_pstr);
}
return *this;
}
String String::operator+(const String &that) const
{
String newString;
if (!that.m_pstr) {
newString = *this;
} else if (!this->m_pstr) {
newString = that;
} else {
newString.m_pstr = new char[strlen(this->m_pstr) +
strlen(that.m_pstr) + 1];
strcpy(newString.m_pstr, this->m_pstr);
strcat(newString.m_pstr, that.m_pstr);
}
return newString;
}
bool String::operator==(const String &that) const
{
if (strlen(this->m_pstr) != strlen(that.m_pstr)) {
return false;
} else {
return strcmp(this->m_pstr, that.m_pstr)?false:true;
}
}
char String::operator[](int index) const
{
if (index > 0 && index < strlen(this->m_pstr)) {
return this->m_pstr[index];
} else {
return '\0';
}
}
ostream &operator<<(ostream &os, const String &that)
{
os << that.m_pstr;
return os;
}
istream &operator>>(istream &is, String &that)
{
is >> that.m_pstr;
return is;
}
int String::length(void) const
{
return strlen(this->m_pstr);
}
char *String::c_str(void) const
{
return this->m_pstr;
}
String &String::exchange(void)
{
for (int i = 0; i < strlen(m_pstr) / 2; i++) {
m_pstr[i] ^= m_pstr[strlen(m_pstr) - i - 1];
m_pstr[strlen(m_pstr) - i - 1] ^= m_pstr[i];
m_pstr[i] ^= m_pstr[strlen(m_pstr) - i - 1];
}
return *this;
}