String类(C++练习二)

字符串类(String),熟悉内存管理与拷贝控制

  • 类定义
  • #include <iostream>
    //#include <cstring>
    using std::cout;
    using std::cin;
    
    class String{
        using iterator = char *;
        friend std::ostream &operator<< (std::ostream &, const String &);
        friend std::istream &operator>> (std::istream &, String &);
        friend String operator + (const String &, const String &);
        friend String operator + (const String &, const char *);        //对于非类内的函数,必须参数中存在类类型的参数;
        friend String operator + (const char *, const String &);        //否则会与默认类型的操作符冲突
        friend unsigned int getline(std::istream &, String &);
    public:
        String(const char *rhs = "hello, world");    //构造函数,默认为"hello, world" 通常我们可以默认为NULL
        String(const String &);            //拷贝构造函数
        String &operator= (const String&);    //拷贝赋值运算符
        String &operator= (const char *);    //拷贝赋值运算符
        String & operator += (const String&);
        String & operator += (const char *);
        char operator[] (int);
        iterator begin();
        iterator end();
        String & push_back(const char);
        String & clear();
    
        ~String() { delete [] data; }    //析构函数
    private:
        char *data;
    };
    std::ostream & operator<< (std::ostream &, const String &);
    std::istream &operator>> (std::istream &, String &);
    
    inline String::String(const char *rhs)
    {
        if (!rhs)                    //必须先检查rhs是否为NULL;对于NULL的拷贝,会去读取未知地址
            data = new char[1]{0};    //因为我们的析构函数调用了delete,所以必须开辟一个空间,
                                    //否则代码在调用析构函数时会delete一个错误空间
        else {
            data = new char[strlen(rhs) + 1];
            strcpy(data, rhs);
        }
    }
    
    inline String& String::operator= (const String& rhs)    //拷贝赋值运算
    {
        this->data = new char[strlen(rhs.data) + 1];
        strcpy(this->data, rhs.data);
        return *this;
    }
    
    inline String & String::operator= (const char *rhs)    //拷贝赋值运算符
    {
        this->data = new char[strlen(rhs) + 1];
        strcpy(this->data, rhs);
        return *this;
    }
  • 类方法实现
  • #include "String.h"
    
    inline String::String(const String &rhs)            //拷贝构造函数
    {
        data = new char[strlen(rhs.data) + 1];        //每次都要 +1 的原因是strlen不包含最后的‘\0‘
        strcpy(data, rhs.data);
    }
    
    std::ostream &operator<< (std::ostream &os, const String &rhs)
    {
        os << rhs.data;
        return os;
    }
    
    std::istream& operator >> (std::istream &is, String &rhs)
    {
        is >> rhs.data;
        return is;
    }
    
    String & String::operator += (const String &rhs)
    {
        if (!rhs.data)            //如果要加的类的数据为NULL,则不需要处理了
            return *this;
        else if (!data)            //如果原来的数据为NULL,则直接把后来的数据拷贝过来;由于上面的判断,所以rhs.data != NULL;
        {
            this->data = new char[strlen(rhs.data) + 1];
            strcpy(this->data, rhs.data);
            return *this;
        }
        else                    //data != NULL && rhs.data != NULL
        {
            char *tmp = new char[strlen(this->data) + 1];
            strcpy(tmp, this->data);
            this->data = new char[strlen(data) + strlen(rhs.data) + 1];
            strcpy(data, tmp);
            strcat(data, rhs.data);
            free(tmp);
            return *this;
        }
    }
    
    String & String::operator += (const char * rhs)
    {
        if (!rhs)            //如果要加的类的数据为NULL,则不需要处理了
            return *this;
        else if (!data)            //如果原来的数据为NULL,则直接把后来的数据拷贝过来;由于上面的判断,所以rhs.data != NULL;
        {
            this->data = new char[strlen(rhs) + 1];
            strcpy(this->data, rhs);
            return *this;
        }
        else                    //data != NULL && rhs.data != NULL
        {
            char *tmp = new char[strlen(this->data) + 1];
            strcpy(tmp, this->data);
            this->data = new char[strlen(data) + strlen(rhs) + 1];
            strcpy(data, tmp);
            strcat(data, rhs);
            free(tmp);
            return *this;
        }
    }
    
    String operator + (const String &lhs, const String &rhs)
    {
        String tmp(lhs);
        tmp += rhs;
        return tmp;
    }
    
    String operator + (const String &lhs, const char *rhs)
    {
        String tmp(lhs);
        tmp += rhs;
        return tmp;
    }
    
    String operator + (const char *lhs, const String &rhs)
    {
        String tmp(lhs);
        tmp += rhs;
        return tmp;
    }
    
    String::iterator String::begin()
    {
        return data;
    }
    
    String::iterator String::end()
    {
        return data + strlen(data);
    }
    
    char String::operator[] (int index)
    {
        if (index > strlen(data) - 1 || index < 0)
        {
            cout << "index error";
            return 0;
        }
        else
        return *(data + index);
    }
    
    String & String::push_back(const char ch)
    {
        char *tmp = new char[strlen(data) + 2];
        strcpy(tmp, data);
        *(tmp + strlen(data)) = ch;            //data + strlen(data)是原来的‘\0‘处
        *(tmp + strlen(data) + 1) = ‘\0‘;
        data = new char[strlen(data) + 2];
        strcpy(data, tmp);
        //free(tmp);
        delete[] tmp;    //delete [] tmp = free(tmp) : 怀疑delete就是把free封装了
        return *this;
    }
    
    String & String::clear()
    {
        delete[] data;
        data = new char[]{0};
        return *this;
    }
    unsigned int getline(std::istream &is, String & rhs)
    {
        char tmp;
        rhs.clear();
        while (is.get(tmp))
        {
            if (tmp && tmp != ‘\n‘)
                rhs.push_back(tmp);
            else
                break;
        }
        return strlen(rhs.data);
    }
  • 先把开始的写好了,后面可以一直重用它,比如 += 和 +;
  • 析构函数中需要使用delete [] data,是因为很多操作中都需要开辟空间,所以在默认构造函数中虽然里面不放东西但是还需要开辟一个空间,因为当这个类由于某些原因调用析构函数时,需要有一块空间给delete使用
  • 使用智能指针应该也是可以的,这样的话就不需要delete了
时间: 2024-12-19 03:50:38

String类(C++练习二)的相关文章

一大波Java来袭(四)String类、StringBuilder类、StringBuffer类对比

本文主要介绍String类.StringBuffer类.StringBuilder类的区别  : 一.概述 (一)String 字符串常量,但是它具有不可变性,就是一旦创建,对它进行的任何修改操作都会创建一个新的字符串对象. (二)StringBuffer 字符串可变量,是线程安全的,和StringBuilder类提供的方法完全相同. 区别在于StringBuffer每个方法中前面添加了"synchronized",保证其是线程安全的. (三)StringBuilder 字符串可变量,

一大波Java来袭(四)String类、StringBuilder类、StringBuffer类对照

本文主要介绍String类.StringBuffer类.StringBuilder类的差别  : 一.概述 (一)String 字符串常量.可是它具有不可变性,就是一旦创建,对它进行的不论什么改动操作都会创建一个新的字符串对象. (二)StringBuffer 字符串可变量,是线程安全的,和StringBuilder类提供的方法全然同样. 差别在于StringBuffer每一个方法中前面加入了"synchronized",保证其是线程安全的. (三)StringBuilder 字符串可

String类 (二) ~正则表达式

正则表达式 1. 概述 正则表达式本质就是一个 字符串,用于进行数据格式的验证. 通常情况下,正则表达式使用  ^ (异或符号)开头,使用$  (美元符号) 结尾.        可以省略,但是推荐写上 2.常用规则 字符类: [abc]     -表示可以出现a.b 或c中的任意字符 [^abc]   -表示可以出现任意字符,除了a.b 及c [a-zA-Z]  -表示可以出现a到z 和 A到Z之间的任意字符.即可以出现所有的字母. 预定字: \d  -表示可以出现任何数字,相当于[0~9]

C#拾遗之String类(二)

接上一篇文章继续说String类 六,字符串的删除 字符串的删除是通过Remove方法实现的,格式为: (1)字符串.Remove(开始位置) (2)字符串.Remove(开始位置,移除数) 其中,开始位置是指字符串的索引,是一个整数,且小于字符串的长度.第一种格式,是将字符串开始位置后的所有子子符删除,而第二种是将从开始位置开始数到移除数位置的字符删除. 例六,实现字符串str的删除 <span style="font-size:18px;">using System;

JDK中String类的源码分析(二)

1.startsWith(String prefix, int toffset)方法 包括startsWith(*),endsWith(*)方法,都是调用上述一个方法 1 public boolean startsWith(String prefix, int toffset) { 2 char ta[] = value; 3 int to = toffset; 4 char pa[] = prefix.value; 5 int po = 0; 6 int pc = prefix.value.l

新手学JAVA(二)----String类与StringBuffer类的区别

在Java中有两种字符串的操作:String类和StringBuffer类(缓冲字符串处理类). 下面先简单的说一下两者的区别. String类和StringBuffer类都提供了相应的方法实现字符串的操作,但二者略有不同. (1) String类 该类一旦产生一个字符串,其对象就不可变.String类的内容和长度是固定的.如果程序需要获得字符串的信息需要调用系统提供的各种字符串操作方法实现.虽然通过各种系统方法可以对字符串施加操作,但这并不改变对象实例本身,而是生成一个新的实例.系统为Stri

java String 类 基础笔记

字符串是一个特殊的对象. 字符串一旦初始化就不可以被改变. String s = "abc";//存放于字符串常量池,产生1个对象 String s1=new String("abc");//堆内存中new创建了一个String对象,产生2个对象 String类中的equals比较字符串中的内容. 常用方法: 一:获取 1.获取字符串中字符的个数(长度):length();方法. 2.根据位置获取字符:charAt(int index); 3.根据字符获取在字符串中

String类

一.概述 Sting s1 = "abc";    //s1是一个类类型变量,"abc"是一个对象. String s2 = new String("abc"); //s1 . s2 的区别: 前者在内存中有一个对象,后者在内存中有两个对象. s1.equals(s2) 为true  因为 String复写了equals方法 二.常见的功能-获取和判断 获取: 1.int length(); 获取长度 2.char chatAt(int inde

String类replaceAll方法正则替换深入分析

作者网址: https://my.oschina.net/shipley/blog/98973 背景:      前几天有人发了一个关于下面问题的贴,对这个有点好奇,故花时间做了点研究.        对单个反斜杠字符串替换成双斜杠的Java实现如下:    String s = "\\";    方法一:String sr1 = s.replaceAll("\\\\", "\\\\\\\\");    方法二:String sr1 = s.re

Java String类的常用方法

String(byte[ ] bytes):通过byte数组构造字符串对象. String(char[ ] value):通过char数组构造字符串对象. String(Sting original):构造一个original的副本.即:拷贝一个original. String(StringBuffer buffer):通过StringBuffer数组构造字符串对象. byte[] b = {'a','b','c','d','e','f','g','h','i','j'}; char[] c =