C++实现string类

本文详细介绍了如何在C++中实现一个自定义的string类,包括默认构造函数、含参构造函数、析构函数、拷贝构造函数、赋值运算符和加法运算符的实现,以及内存管理的注意事项,如防止内存泄漏和深拷贝。
摘要由CSDN通过智能技术生成


string类

写一个string类,能够完成string类的操作:

  1. 构造函数,能使用=构造,构造函数传入的参数为const char* 类型
  2. 拷贝构造函数
  3. 析构函数
  4. operator =
  5. operator +
  6. operator +=
  7. operator <<
  8. 从string类型转换成const char*类型,data()方法
  9. 将string转成int类型
  10. 统计string的长度,也就是size()方法
  11. 清空字符串
  12. 判断字符串是否为空
  13. 追加append函数,类似于+=

数据成员

  • char* ptr:指向堆内存空间,从堆内存申请空间。
  • int len:记录字符串实际长度,不包含结束符。

默认构造函数

默认构造函数中,为ptr申请一个字节的堆内存,这样任何情况下,ptr都不为nullptr,避免了ptr是否为nullptr的情况,在随时访问的时候,就可以少写很多if判断。

myString::myString(){
    ptr = (char*)malloc(1); //为ptr申请一个字节的堆内存
    memset(ptr,0,1);
    len = 0; //字符串实际长度为0
}

含参构造函数

  1. 传入一个const char* r,让构造函数接受字符串字面量作为参数,因为字符串字面量在C++中是const char[]类型的,自然会转换为const char*类型。
  2. 先为ptr申请字符串r长度+1的内存空间,多一个字节是为了保存结束符’\0’。
  3. 再将r所指的内存空间中的内容,拷贝给ptr所指的内存空间,使用memmove,memmove被用来将字符串从一个内存位置复制到另一个位置。
  4. 在实际的调用中,用一个“=”赋值的时候,就会调用含餐构造函数。
myString::myString(const char* r){
// 先为ptr申请字符串r长度+1的内存空间,多一个字节是为了保存结束符'\0'
    len = strlen(r);
    ptr = (char*)malloc(len+1);
    memset(ptr,0,len+1);
// 将r所指的内存空间中的内容,拷贝给ptr所指的内存空间,为了避免内存泄漏,使用memmove
    memmove(ptr,r,len+1);
}

析构函数

  1. 释放ptr指向的内存空间
myString::~myString(){
    free(ptr);
}

拷贝构造函数

  1. 因为有指针进行new堆内存操作,需要重写拷贝构造函数进行深拷贝。
  2. 如果不重写拷贝构造函数的话,会调用系统默认的拷贝构造。
  3. 默认的拷贝构造是浅拷贝,在包含堆内存操作的类中,会出现重复释放,造成段错误。
// 拷贝构造,深拷贝
myString::myString(const myString& r){
    //free(ptr);
    len = r.len;
    ptr = (char*)malloc(len+1);
    memset(ptr,0,len+1);// 为p的ptr申请独立的空间
// 将r中的ptr拷贝给p的ptr
    memmove(ptr,r.ptr,len+1); // 拷贝数据
}

赋值运算符

  • 防止自赋值
  • 注意对原本非空指针的释放
myString myString::operator= (const myString& r){
    if(this != &r) { // 防止自赋值
        if(ptr != nullptr)
            free(ptr);
        len = r.len;
        ptr = (char*)malloc(len+1);
        memset(ptr, 0, len+1);
        memmove(ptr, r.ptr, len+1);
    }
    return *this; // 应该返回对象的引用
}

加号运算符和+=运算符

  • p1 = p1+“hello”
  • p1 = p1+p2; 两种都有可能,要写全参数类型
  • +=运算符和+类似
// p1 = p1+"hello";
myString myString::operator+(const char* r){
    // 创建新的对象,新对象的长度以及ptr指向内存空间是this+r的总和
    myString newStr;
    free(newStr.ptr); //这里要把newStr.ptr指向的内存进行释放,否则会出现内存泄漏
    newStr.len = this->len+strlen(r);
    newStr.ptr = (char*)malloc(newStr.len+1);
    memset(newStr.ptr,0,newStr.len+1);
    memmove(newStr.ptr,ptr,len);
    strcat(newStr.ptr,r);
    return newStr;
}

// p1 = p1+p2
myString myString::operator+(const myString& r){
    myString newStr;
    free(newStr.ptr); //这里要把newStr.ptr指向的内存进行释放,否则会出现内存泄漏
    newStr.len = this->len+r.len;
    newStr.ptr = (char*)malloc(newStr.len+1);
    memset(newStr.ptr,0,newStr.len+1);
    memmove(newStr.ptr,ptr,len);
    strcat(newStr.ptr,r.ptr);
    return newStr;
}
myString myString::operator+=(const char* r){
    char* temp = ptr;
    int l = len; // 保存原来的ptr和len
    this->len = this->len+strlen(r);
    this->ptr = (char*)malloc(this->len+1); //ptr指向新的内存空间
    memset(ptr,0,len+1);
    memmove(ptr,temp,l); // 把原来的ptr内容拷贝给新的ptr
    strcat(ptr,r);
    free(temp);
    return *this;
}


myString myString::operator+=(const myString& r){
    char* temp = ptr;
    int l = len;
    len = len+r.len;
    ptr = (char*)malloc(len+1);
    memset(ptr,0,len+1);
    memmove(ptr,temp,l);
    strcat(ptr,r.ptr);
    free(temp); //temp记得free
    return *this;
}

代码

#include<iostream>
#include <string.h>

using std::cout;
using std::endl;

/**
 * 当myString对象没有保存任何字符串的时候,应该至少为该对象中的ptr申请至少一个字节的空间
 * 这样任何情况下,ptr都不为nullptr,避免了ptr是否为nullptr的情况,在随时访问的时候,
 * 就可以少写很多if判断。
 *  · 无参构造函数要重写。
 *  · 因为有指针进行new堆内存操作,默认的拷贝构造是浅拷贝,需要重写拷贝构造,否则会出现重复释放,造成段错误。
*/
class myString{
public:
    myString(); //无参构造函数
    myString(const char* r); //单参构造函数
    myString(const myString& r); //单参构造函数
    ~myString();
    void show(){cout<<ptr<<endl;}
    int size(){return len;}
    void clear();
    bool empty();
    myString operator= (const myString& r);
    myString operator+ (const char* r);
    myString operator+(const myString& r);
    myString operator+= (const char* r);
    myString operator+= (const myString& r);
    char operator[](int n);

    void append(const char* r);
    void append(const myString& r);

    friend std::ostream& operator<< (std::ostream& out, const myString& r);
    friend std::istream& operator>> (std::ostream& in, myString& r);

    const char* data(){return this->ptr;};
    int toInt();
private:
    char* ptr; //指向堆内存空间
    int len; // 字符串实际长度,不包含结束符
};

myString::myString(){
    ptr = (char*)malloc(1); //为ptr申请一个字节的堆内存
    memset(ptr,0,1);
    len = 0;
}

myString::myString(const char* r){
// 先为ptr申请字符串r长度+1的内存空间,多一个字节是为了保存结束符'\0'
    len = strlen(r);
    ptr = (char*)malloc(len+1);
    memset(ptr,0,len+1);
// 将r所指的内存空间中的内容,拷贝给ptr所指的内存空间,为了避免内存泄漏,使用memmove
    memmove(ptr,r,len+1);
}

// 拷贝构造,深拷贝
myString::myString(const myString& r){
    len = r.len;
    ptr = (char*)malloc(len+1);
    memset(ptr,0,len+1);// 为p的ptr申请独立的空间
// 将r中的ptr拷贝给p的ptr
    memmove(ptr,r.ptr,len+1); // 拷贝数据
}

myString::~myString(){
    free(ptr);
}

void myString::clear(){
    free(ptr);
    ptr=(char*) malloc(1);
    memset(ptr,0,1);
    len = 0;
}

bool myString::empty(){
    return !len;
}

myString myString::operator= (const myString& r){
    if(this != &r) { // 防止自赋值
        if(ptr != nullptr)
            free(ptr);
        len = r.len;
        ptr = (char*)malloc(len+1);
        memset(ptr, 0, len+1);
        memmove(ptr, r.ptr, len+1);
    }
    return *this; // 应该返回对象的引用。
}

// p1 = p1+"hello";
myString myString::operator+(const char* r){
    // 创建新的对象,新对象的长度以及ptr指向内存空间是this+r的总和
    myString newStr;
    free(newStr.ptr); //这里要把newStr.ptr指向的内存进行释放,否则会出现内存泄漏
    newStr.len = this->len+strlen(r);
    newStr.ptr = (char*)malloc(newStr.len+1);
    memset(newStr.ptr,0,newStr.len+1);
    memmove(newStr.ptr,ptr,len);
    strcat(newStr.ptr,r);
    return newStr;
}

// p1 = p1+p2
myString myString::operator+(const myString& r){
    myString newStr;
    free(newStr.ptr); //这里要把newStr.ptr指向的内存进行释放,否则会出现内存泄漏
    newStr.len = this->len+r.len;
    newStr.ptr = (char*)malloc(newStr.len+1);
    memset(newStr.ptr,0,newStr.len+1);
    memmove(newStr.ptr,ptr,len);
    strcat(newStr.ptr,r.ptr);
    return newStr;
}

myString myString::operator+=(const char* r){
    char* temp = ptr;
    int l = len; // 保存原来的ptr和len
    this->len = this->len+strlen(r);
    this->ptr = (char*)malloc(this->len+1); //ptr指向新的内存空间
    memset(ptr,0,len+1);
    memmove(ptr,temp,l); // 把原来的ptr内容拷贝给新的ptr
    strcat(ptr,r);
    free(temp);
    return *this;
}


myString myString::operator+=(const myString& r){
    char* temp = ptr;
    int l = len;
    len = len+r.len;
    ptr = (char*)malloc(len+1);
    memset(ptr,0,len+1);
    memmove(ptr,temp,l);
    strcat(ptr,r.ptr);
    free(temp); //temp记得free
    return *this;
}

char myString::operator[](int n){
    return ptr[n];
}

void myString::append(const char* r){
    char* temp = ptr;
    int l = len; // 保存原来的ptr和len
    this->len = this->len+strlen(r);
    this->ptr = (char*)malloc(this->len+1); //ptr指向新的内存空间
    memset(ptr,0,len+1);
    memmove(ptr,temp,l); // 把原来的ptr内容拷贝给新的ptr
    strcat(ptr,r);
    free(temp);
}

void myString::append(const myString& r){
    char* temp = this->ptr;
    int l = len;
    len = len+r.len;
    ptr = (char*)malloc(len+1);
    memset(ptr,0,len+1);
    memmove(ptr,temp,l);
    strcat(ptr,r.ptr);
    free(temp); //temp记得free
}

std::ostream& operator<< (std::ostream& out, const myString& r){
    out<<r.ptr;
    return out;
}

std::istream& operator>> (std::ostream& in, myString& r){
    char buf[1024];
    std::cin>>buf;
    free(r.ptr);
    r.len = strlen(buf);
    r.ptr = (char*)malloc(r.len+1);
    memset(r.ptr,0,r.len+1);
    memmove(r.ptr,buf,r.len+1);

}

int myString::toInt(){
    return atoi(this->ptr);
}

int main(){
    myString str = "hello"; // 转换构造函数,也就是单参构造函数
    myString ptr(str); // 拷贝构造
    myString atp = str; //拷贝构造
    ptr = str; //运算符 operator=
    ptr = ptr + " world";
    ptr.show(); 
    myString str2 = " world";
    str2 = str+str2;
    str += " world";
    str.show();
    ptr+=str2;
    ptr.show();
    atp.append(" world");
    atp.show();
    return 0;
}
  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值