【C++】string类的模拟实现(下)

简介: 【C++】string类的模拟实现(下)

2.数据删除

对于数据的删除,一般来说就是尾删和在任意位置删除。

1. pop_back

尾删很简单,我们只需要把最后一个有效字符的值替换成\0,然后更改_size即可

void pop_back()
{
    _str[--_size] = '\0';
}


2. erase

erase的实现分为两种情况

  1. 当删除的长度大于pos位置之后的长度,或者为npos时,直接删除后续所有的值
  2. 当len小于后续长度时,挪动数据
string& erase(size_t pos, size_t len = npos)
{
    assert(pos < _size);
    if (len == npos || pos + len >= _size)
    {
        _str[pos] = '\0';
        _size = 0;
    }
    //挪动数据
    else
    {
        strcpy(_str + pos, _str + pos + len);
        _size -= len;
    }
    return *this;
}


3.数据查找

find:从pos位置开始查找字符或字符串,找到返回下标,找不到返回npos

1. 查找字符

size_t find(size_t pos, char ch)
{
    assert(pos < _size);
    for (size_t i = 0; i < _size; ++i)
    {
        if (_str[i] == ch)
            return i;
    }
    return npos;
}


2. 查找字符串

对于字符串的查找我们可以借用strstr函数实现

size_t find(size_t pos, const char* str)
{
    assert(pos < _size);
    const char* ptr = strstr(_str, str);
    if (ptr == nullptr)
    {
        return npos;
    }
    else
    {
        return ptr - _str;
    }
}


注:修改是建立在查找上的,所以这里就不专门讲解了


7.流插入和流提取


对于流插入和流提取的重载,我们在日期类的时候就已经讲过,不能重载成成员函数,如果重载成成员函数会导致this指针抢占第一个位置。所以需要重载成全局函数,然后在类里面设成友元。

1. 流插入

ostream& operator<<(ostream& _cout, const zht::string& s)
{
    for (size_t i = 0; i < s.size(); i++)
    {
        _cout << s[i];
    }
    return _cout;
}


2. 流提取

对于流提取,我们使用cin或者scanf是没有办法拿到空格和\0的,所以这里需要使用get函数来拿到

istream& operator>>(istream& _cin, zht::string& s)
{
    s.clear();
    char ch = _cin.get();
    while (ch != ' ' && ch != '\0')
    {
        s += ch;
    ch = _cin.get();
    }
    return _cin;
}


但是,对于上述的情况,如果需要扩容的话,会导致频繁扩容,所以我们在这里使用一个临时数组来存放,然后统一尾插到string中去。

istream& operator>>(istream& _cin, zht::string& s)
{
    s.clear();
    char buff[128] = { '\0' };
    size_t i = 0;
    char ch = _cin.get();
    while (ch != ' ' && ch != '\0')
    {
        if (i == 127)
        {
            s += buff;
            i = 0;
        }
        buff[i++] = ch;
        ch = _cin.get();
    }
    if (i > 0)
    {
        buff[i] = '\0';
        s += buff;
    }
    return _cin;
}


8.其他接口


在上文中,我们提到了一个swap函数,这个swap函数在使用的时候,形参只有一个,这个swap函数就是在string类中重载的一个函数。

为什么要在string里面重新重载一个swap函数呢?

这是因为算法库里面实现的swap函数是一个模板

3dde91bd4c6b905f72bfadb8aac95207.png

可以看到,无论对于什么类型,他都会无脑的拷贝构造,这样其实对于string这种使用new在堆上开辟空间的类效率是不高的,所以需要在类内重新写一个swap函数,将类内的成员变量进行交换即可,这样就能省去new和delete的消耗。

void swap(string& s)
{
    std::swap(_str, s._str);
    std::swap(_size, s._size);
    std::swap(_capacity, s._capacity);
}

2. c_str

对于Linux操作系统,它是使用C语言写的,所以它的系统接口也都是C形式的接口,而不支持string,所以我们在进行系统调用的时候,需要将string转换成C字符串的形式传参。c_str就是将string类返回成C字符串形式。

char* c_str()
{
    return _str;
}
const char* c_str() const
{
    return _str;
}


载一个swap函数呢?


这是因为算法库里面实现的swap函数是一个模板

[外链图片转存中…(img-CP2s20jF-1681724759328)]

可以看到,无论对于什么类型,他都会无脑的拷贝构造,这样其实对于string这种使用new在堆上开辟空间的类效率是不高的,所以需要在类内重新写一个swap函数,将类内的成员变量进行交换即可,这样就能省去new和delete的消耗。

void swap(string& s)
{
    std::swap(_str, s._str);
    std::swap(_size, s._size);
    std::swap(_capacity, s._capacity);
}


2. c_str

对于Linux操作系统,它是使用C语言写的,所以它的系统接口也都是C形式的接口,而不支持string,所以我们在进行系统调用的时候,需要将string转换成C字符串的形式传参。c_str就是将string类返回成C字符串形式。

char* c_str()
{
    return _str;
}
const char* c_str() const
{
    return _str;
}


相关文章
|
24天前
|
存储 安全 C语言
C++ String揭秘:写高效代码的关键
在C++编程中,字符串操作是不可避免的一部分。从简单的字符串拼接到复杂的文本处理,C++的string类为开发者提供了一种更高效、灵活且安全的方式来管理和操作字符串。本文将从基础操作入手,逐步揭开C++ string类的奥秘,帮助你深入理解其内部机制,并学会如何在实际开发中充分发挥其性能和优势。
|
24天前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
2天前
|
设计模式 安全 C++
【C++进阶】特殊类设计 && 单例模式
通过对特殊类设计和单例模式的深入探讨,我们可以更好地设计和实现复杂的C++程序。特殊类设计提高了代码的安全性和可维护性,而单例模式则确保类的唯一实例性和全局访问性。理解并掌握这些高级设计技巧,对于提升C++编程水平至关重要。
31 16
|
2天前
|
缓存 安全 Java
《从头开始学java,一天一个知识点》之:字符串处理:String类的核心API
🌱 **《字符串处理:String类的核心API》一分钟速通!** 本文快速介绍Java中String类的3个高频API:`substring`、`indexOf`和`split`,并通过代码示例展示其用法。重点提示:`substring`的结束索引不包含该位置,`split`支持正则表达式。进一步探讨了String不可变性的高效设计原理及企业级编码规范,如避免使用`new String()`、拼接时使用`StringBuilder`等。最后通过互动解密游戏帮助读者巩固知识。 (上一篇:《多维数组与常见操作》 | 下一篇预告:《输入与输出:Scanner与System类》)
31 11
|
8天前
|
Java
课时14:Java数据类型划分(初见String类)
课时14介绍Java数据类型,重点初见String类。通过三个范例讲解:观察String型变量、&quot;+&quot;操作符的使用问题及转义字符的应用。String不是基本数据类型而是引用类型,但使用方式类似基本类型。课程涵盖字符串连接、数学运算与字符串混合使用时的注意事项以及常用转义字符的用法。
|
6天前
|
安全 C++
【c++】继承(继承的定义格式、赋值兼容转换、多继承、派生类默认成员函数规则、继承与友元、继承与静态成员)
本文深入探讨了C++中的继承机制,作为面向对象编程(OOP)的核心特性之一。继承通过允许派生类扩展基类的属性和方法,极大促进了代码复用,增强了代码的可维护性和可扩展性。文章详细介绍了继承的基本概念、定义格式、继承方式(public、protected、private)、赋值兼容转换、作用域问题、默认成员函数规则、继承与友元、静态成员、多继承及菱形继承问题,并对比了继承与组合的优缺点。最后总结指出,虽然继承提高了代码灵活性和复用率,但也带来了耦合度高的问题,建议在“has-a”和“is-a”关系同时存在时优先使用组合。
45 6
|
27天前
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)
|
8天前
|
存储 JavaScript Java
课时44:String类对象两种实例化方式比较
本次课程的主要讨论了两种处理模式在Java程序中的应用,直接赋值和构造方法实例化。此外,还讨论了字符串池的概念,指出在Java程序的底层,DOM提供了专门的字符串池,用于存储和查找字符串。 1.直接赋值的对象化模式 2.字符串池的概念 3.构造方法实例化
|
27天前
|
C++
模拟实现c++中的string
模拟实现c++中的string
|
24天前
|
安全 编译器 C语言
【C++篇】深度解析类与对象(中)
在上一篇博客中,我们学习了C++类与对象的基础内容。这一次,我们将深入探讨C++类的关键特性,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载、以及取地址运算符的重载。这些内容是理解面向对象编程的关键,也帮助我们更好地掌握C++内存管理的细节和编码的高级技巧。