我是靠谱客的博主 忧郁人生,最近开发中收集的这篇文章主要介绍MySTL实现之MyStringMySTL实现String类的实现总结,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

MySTL实现

实现STL库中的基础容器及基本函数


文章目录

  • MySTL实现
  • String类的实现
    • MyString头文件
    • 具体实现
      • 1.构造函数
      • 2.析构函数
      • 3.重载
        • 1)重载=
        • 2)重载+=
        • 3)重载==
        • 4)重载[]
        • 5)重载<<
      • 4.其他成员函数
    • 简单测试
  • 总结


String类的实现

对string类的基本功能进行复现,找到了一些错误和c++编程中的细节问题,都在此记录下来。MyString中实现了基本的构造函数、析构函数,重载了常用符号,并且给出了一些常用函数的实现。

在实现过程中,对于是否加入const有两种情况:1.在参数前加入说明该函数不更改此参数;2.在函数后加入说明该函数不更改成员的值。

MyString头文件

class MyString {
private:
char* m_data;//指针指向字符数组,4字节
size_t m_size;//字符串长度
public:
//构造函数
MyString(const char* cstr = 0);//1、无参构造 2、使用c风格字符串构造
MyString(const MyString& str);//3、拷贝构造
MyString(int n, const char c);//4、使用n个字符c初始化
//析构函数
~MyString();
// 重载=
MyString& operator=(const MyString& str);//重载MyString=MyString
//重载+=
MyString& operator+=(const MyString& str);
//重载==
bool operator==(const MyString& str);
//重载[]
char& operator[](int n);
//重载<<
friend ostream& operator<<(ostream& out, MyString& str);//重载<<声明为友元函数
//返回C风格字符串
char* get_c_str() const { return m_data; }
//返回字符串长度
size_t
size() const { return m_size; }
//返回由pos开始的n个字符组成的字符串
MyString substr(int pos , int n) const;
//在pos处插入,结果传入原先存在的变量中,返回引用
MyString& insert(int pos, const MyString& str);
//删除从pos开始的n个字符
MyString& erase(int pos, int n);
//字符串比较
int compare(const MyString& str) const;
//获取某位字符
char& at(int n);
//查找字符子串,从pos开始返回第一个字母的位置
//缺省时从头开始,带参形参写在后面
int find(const MyString& str, int pos = 0);
int find(const char* ch, int pos = 0);
//split方法,按字符切分字符串,返回MyString数组
vector<MyString> split(const MyString& flag);
};
#endif // _MYSTRING_

具体实现

以下分别给出每个函数的具体实现、遇到的问题和需要关注的细节。

1.构造函数

在声明构造函数时,若有默认参数,则不应该再次声明和该默认参数相同的构造函数,例如:

MyString(const char* cstr = 0);
MyString();//无参构造函数和上述构造函数的默认参数情况重合,会提示多个默认构造函数
MyString::MyString(const char* cstr) {
if (cstr) {
m_data = new char[strlen(cstr) + 1];
strcpy(m_data, cstr);
m_size = strlen(cstr);
}
else {//对应无参构造函数
//传入空字符串,创建空字符串
m_data = new char[1];
*m_data = '';
m_size = 0;
}
}
MyString::MyString(const MyString& str) {//拷贝构造函数,深拷贝
m_data = new char[strlen(str.m_data) + 1];//重新申请空间
strcpy(m_data, str.m_data);
m_size = strlen(str.m_data);
}
MyString::MyString(int n, const char c) {
if(n < 0)	throw exception("无效的个数!");
m_data = new char[n + 1];
m_size = n;
int i;
for (i = 0; i < m_size; i++) {
m_data[i] = c;
}
m_data[i] = '';
}

2.析构函数

MyString::~MyString() {
delete[] m_data;
}

3.重载

1)重载=

两个参数格式,传入MyString或c风格字符串,在进行连续等于时,需要返回值为引用类型,所以不能设计为void

MyString& MyString::operator=(const MyString& str) {
//必须判断是否是自我赋值,若无判断会直接删除当前空间,返回产生野指针
if (this == &str) {
return *this;
}
delete[] m_data;//1.清空原有空间
m_data = new char[strlen(str.m_data) + 1];//2.重新申请空间
strcpy(m_data, str.m_data);//3.复制
m_size = strlen(str.m_data);
return *this;
}

2)重载+=

MyString& MyString:: operator+=(const MyString& str) {
char* pre = new char[strlen(m_data) + 1];
strcpy(pre, m_data);//存储原字符串
delete[] m_data;
m_data = new char[strlen(pre) + strlen(str.m_data) + 1];
m_size = strlen(pre) + strlen(str.m_data);
strcpy(m_data, pre);
strcat(m_data, str.m_data);
delete[] pre;//清除申请空间,防止内存泄漏
return *this;
}

3)重载==

根据内部函数compare返回结果

bool MyString::operator==(const MyString& str) {
if (this->compare(str) == 0)
return true;
else
return false;
}

4)重载[]

使用[]取值不会进行越界检查,越界会直接中断程序

char& MyString::operator[](int n) {
return m_data[n];
}

5)重载<<

通过内部函数get_c_str()在流对象中返回c风格字符串

ostream& operator<<(ostream& out, MyString& str) {
out << str.get_c_str();
return out;
}

4.其他成员函数

当传入参数为c风格字符串时,会首先调用构造函数生成MyString对象,再进入该函数,并在函数结束时调用析构函数销毁该对象。

在函数中使用new在堆中申请空间,需要在函数结束前手动销毁空间。

1)从pos为开始,复制n位

MyString MyString::substr(int pos, int n) const {
//验证pos合法性
//验证pos+n是否超过长度
int len = n;
if (pos < 0 || pos >= m_size || n < 0) {
//抛出越界异常
throw exception("无效的索引位置!");
}
else if (pos + n > m_size) {
len = m_size - pos;
}
char* res = new char[len + 1];
int i;
for (i = 0; i < len; i++) {
res[i] = m_data[pos + i];
}
res[i] = '';
MyString reslut(res);//重新包装为MyString对象
delete[] res;
return reslut;//在函数结束后会调用reslut对象的析构函数,在接收端调用拷贝构造函数生成结果对象
}

2)在pos位插入字符串

MyString& MyString::insert(int pos, const MyString& str) {
//验证pos合法性
if (pos < 0 || pos >= m_size) {
//抛出越界异常
throw exception("无效的索引位置!");
}
char* pre = new char[m_size + 1];
strcpy(pre, m_data);
delete[] m_data;
m_data = new char[strlen(pre) + strlen(str.m_data) + 1];
m_size = strlen(pre) + strlen(str.m_data);
int i;
for (i = 0; i < pos; i++) {
m_data[i] = pre[i];
}
for (int j = 0; j < strlen(str.m_data); j++) {
m_data[i++] = str.m_data[j];
}
for (int j = 0; j < strlen(pre) - pos; j++) {
m_data[i++] = pre[pos + j];
}
m_data[i] = '';
delete[] pre;
return *this;
}

3)从pos位删除n位

MyString& MyString:: erase(int pos, int n) {
if (pos < 0 || pos >= m_size) {
//抛出越界异常
throw exception("无效的索引位置!");
}
else if (pos + n > m_size) {
char* pre = new char[m_size + 1];
strcpy(pre, m_data);
delete[] m_data;
m_data = new char[pos + 1];
m_size = pos;
strncpy(m_data, pre, pos);
m_data[pos] = '';
delete[] pre;
return *this;
}
char* pre = new char[m_size + 1];
strcpy(pre, m_data);
delete[] m_data;
m_data = new char[m_size - n + 1];
m_size = m_size - n;
int i;
for (i = 0; i < pos; i++) {
m_data[i] = pre[i];
}
for (int j = pos + n; j < strlen(pre); j++) {
m_data[i++] = pre[j];
}
m_data[i] = '';
delete[] pre;
return *this;
}

4)字符串比较函数,自身大返回1,相等为0,小于为-1

int MyString::compare(const MyString& str) const {
int i = 0, j = 0;
while (m_data[i] != '' && str.m_data[j] != '') {
if ((int)m_data[i] > (int)str.m_data[j]) {
return 1;
}
else if ((int)m_data[i] < (int)str.m_data[j]) {
return -1;
}
i++; j++;
}
if (m_data[i] != '')	return 1;
else if (str.m_data[j] != '')	return -1;
return 0;
}

5)获取某位,会检查数组越界情况

char& MyString::at(int n) {
if (n < 0 || n >= m_size) {
throw exception("无效的索引位置!");
}
return m_data[n];
}

6)查找函数,在主串中pos位起始,查找子串开始位置

int MyString::find(const MyString& str, int pos) {
return this->find(str.m_data, pos);
}
int MyString::find(const char* ch, int pos) {
if (pos >= m_size) {
throw exception("无效的索引位置!");
}
int len = strlen(ch);
if (len > m_size - pos) {
return -1;
}
int i = pos, j = 0;
while (m_data[i] != '' && ch[j] != '') {
while (m_data[i] != '' && ch[j] != ''&& m_data[i] == ch[j]) {
i++; j++;
}
if (m_data[i] == '' || ch[j] == '') {
break;
}
i++;
j = 0;
}
if (ch[j] == '') {
return i - len;
}
if (m_data[i] == '') {
return -1;
}
return -1;
}

7)split函数,将字符串按给定标志切分,放入MyString数组

对于返回数组的函数,在函数内部声明的数组不能返回引用,当函数结束时空间被销毁

vector<MyString> MyString::split(const MyString& flag) {
vector<MyString>res;
int i = 0;
for (; i < m_size;) {
int pos = this->find(flag, i);
if (pos == -1) {
break;
}
MyString str = this->substr(i, pos - i);
res.push_back(str);
i = pos + 1;
}
MyString str = this->substr(i, m_size - i);
res.push_back(str);
return res;
}

简单测试

简单的测试了上述函数,对于很大的字符串和一些边界问题没有深入研究,希望读者可以提出。在该类中借助exception标准异常库只实现了一部分的异常处理功能,还不够完善。

#include"MyString.h"
#include<iostream>
#include<string>
using namespace std;
int main() {
const char* ch = "hello";
MyString str1;
MyString str2(ch);
MyString str3(str2);
MyString str4(10,'c');
str1 = str2;
str1 += str2;
str4 += ch;
MyString str5 = str4.substr(0, 6);
MyString str6 = str4.substr(10, 6);
std::cout << "str1:" << str1 << std::endl;
std::cout << "str1.size():" << str1.size() << std::endl;
std::cout << "str2:" << str2 << std::endl;
std::cout << "str2.size():" << str2.size() << std::endl;
std::cout << "str3:" << str3 << std::endl;
std::cout << "str3.size():" << str3.size() << std::endl;
std::cout << "str4:" << str4 << std::endl;
std::cout << "str4.size():" << str4.size() << std::endl;
std::cout << "str5:" << str5 << std::endl;
std::cout << "str5.size():" << str5.size() << std::endl;
std::cout << "str6:" << str6 << std::endl;
std::cout << "str6.size():" << str6.size() << std::endl;
MyString str7 = "0123456";
str7.insert(6, "7");
std::cout << "str7:" << str7 << std::endl;
std::cout << "str7.size():" << str7.size() << std::endl;
str7.insert(6, str3);
std::cout << "str7:" << str7 << std::endl;
std::cout << "str7.size():" << str7.size() << std::endl;
str7.erase(0, 1);
std::cout << "str7:" << str7 << std::endl;
std::cout << "str7.size():" << str7.size() << std::endl;
cout << "str7.compare(str1):" << str7.compare(str1) << endl;
if (str1 == str2) {
cout << "str1 == str2" << endl;
}
else {
cout << "str1 != str2" << endl;
}
if (str1 == "hellohello") {
cout << "str1 == hellohello" << endl;
}
else {
cout << "str1 != hellohello" << endl;
}
cout << "str1[5]= " << str1[5] << endl;
try {
cout << str1.at(100);
}
catch(exception& e){
cout << e.what() << endl;
}
cout << "str4.find('ccccccc',3):" << str4.find("ccccccc",3) << endl;
cout << "str7.find(str1):" << str7.find(str1) << endl;
cout << "str1.find(str2):" << str1.find(str2) << endl;
cout << "str4.find(str2):" << str4.find(str2) << endl;
MyString str8 = "www.baidu.com";
vector<MyString>ans = str8.split(".");
for (auto it : ans)	cout << it << endl;
return 0;
}

总结

接下来会实现vector容器及相关函数,MyString类文件在该仓库(如果对你有帮助或者你发现了问题都可以在仓库点赞或提交问题)也可以从这里下载。

最后

以上就是忧郁人生为你收集整理的MySTL实现之MyStringMySTL实现String类的实现总结的全部内容,希望文章能够帮你解决MySTL实现之MyStringMySTL实现String类的实现总结所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(48)

评论列表共有 0 条评论

立即
投稿
返回
顶部