C++实现一个简单的String类

本文涉及的产品
实时数仓Hologres,5000CU*H 100GB 3个月
实时计算 Flink 版,5000CU*H 3个月
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
简介: 使用基本的C++知识实现一个简单的String类,这个类中包含了C++常用的知识点。感觉是很有意思的一个小代码片段。跟大家分享一下我的实现,欢迎大家批评指正。

C++实现一个简单的String类

使用基本的C++知识实现一个简单的String类,这个类中包含了C++常用的知识点。感觉是很有意思的一个小代码片段。

跟大家分享一下我的实现,欢迎大家批评指正。

类声明

  1. 该类中包含了三个构造函数:有参数的构造函数,拷贝构造函数已经移动构造函数

  2. 重载了[],=(一个普通赋值运算符,一个移动赋值运算符),+,==四个运算符

  3. 一个用于求字符长度的方法;一个用于获取C语言类型字符串的方法

  4. 以友元的方式重载了输入流>>和输出流<<操作符

头文件(strings.h)

//
// Created by Zhenyu Tan on 2018/10/3.
//
#include <iostream>

class String {
private:
    char* _buffer;
    size_t _length;
    void init(const char* str);

public:
    String(const char* str= nullptr);       // 默认构造函数
    String(const String& other);            // 拷贝构造函数
    String(String&& other) noexcept;        // 移动构造函数
    ~String();                              // 析构函数

    size_t length();
    const char* data();

    char& operator[](size_t index);
    String& operator=(const String& other);
    String& operator=(String&& other) noexcept;
    String operator+(const String& other);
    bool operator==(const String& other);

    friend std::ostream& operator<<(std::ostream& output, const String& str);
    friend std::istream& operator>>(std::istream& input, String& str);
};
AI 代码解读

类实现

源文件(strings.cpp)

//
// Created by Zhenyu Tan on 2018/10/5.
//

#include "strings.h"
#include <cstring>
#include <exception>
#include <iostream>

using std::cout;
using std::ostream;
using std::istream;

size_t String::length() {
    if (0 == _length) {
        _length = std::strlen(_buffer);
    }
    return _length;
}

const char* String::data() {
    return _buffer;
}


void String::init(const char* str) {
    if (nullptr == str) {
        _length = 0;
        _buffer = nullptr;
    } else {
        _length = std::strlen(str);
        _buffer = new char[_length + 1];
        std::strcpy(_buffer, str);
    }
}


String::String(const char* str) {
    init(str);
    cout << "默认构造函数(" << *this << ")\n";
}


String::String(const String& other) {
    // 在类的成员函数中可以访问同类型实例的私有变量
    init(other._buffer);
    cout << "拷贝构造函数(" << *this << ")\n";
}

String::String(String&& other) noexcept {
    // 把other对象掏空用来填充this
    _buffer = nullptr;
    _buffer = other._buffer;
    _length = other._length;
    other._buffer = nullptr;
    other._length = 0;
    cout << "移动构造函数(" << *this << ")\n";
}


String::~String() {
    delete[] _buffer;
    cout << "析构函数(" << *this << ")\n";
}

/*
 * 拷贝构造函数使用传入对象的值生成一个新的对象的实例
 * 赋值运算符是将对象的值复制给一个已经存在的实例
 */
String& String::operator=(const String& other) {
    if (this != &other) {
        delete[] _buffer;
        init(other._buffer);
    }
    cout << "拷贝赋值操作(" << *this << ")\n";
    return *this;
}

/*
 * 移动赋值操作即把参数传进来的对象的所有权转移到this指向的对象
 * 掏空other对象的所有
 */
String& String::operator=(String&& other) noexcept {
   if (this != &other) {
       _buffer = nullptr;
       _buffer = other._buffer;
       _length = other._length;
       other._buffer = nullptr;
       other._length = 0;
   }
    cout << "移动赋值操作(" << *this << ")\n";
    return *this;
}


char& String::operator[](size_t index) {
    if (index >= _length) {
        throw std::out_of_range("Index out of range");
    } else {
        return _buffer[index];
    }
}


bool String::operator==(const String& other) {
    if (_length != other._length) {
        return false;
    } else {
        return 0 == std::strcmp(_buffer, other._buffer);
    }
}

/*
 * 关于是返回对象本身还是返回对象引用
 * 如果函数返回在函数中创建的临时对象,则不要使用引用
 * 如果函数返回的是通过引用或指针传递给它的对象,则应当按引用返回对象
 * 如果先创建一个对象,然后返回改对象的副本,则可以使用返回对象
 */
String String::operator+(const String& other) {
    String _str;
    if (nullptr == _buffer) {
        _str = other;
    } else if (nullptr == other._buffer) {
        _str = *this;
    } else {
        _str._buffer = new char[_length + other._length + 1];
        std::strcpy(_str._buffer, _buffer);
        std::strcat(_str._buffer, other._buffer);
        _str._length = std::strlen(_str._buffer);
    }
    return _str;
}


ostream& operator<<(ostream &output, const String& str) {
    if (nullptr == str._buffer) {
        output << "";
    } else {
        output << str._buffer;
    }
    return output;
}

istream& operator>>(istream &input, String& str) {
    input >> str._buffer;
    return input;
}
AI 代码解读

调用示例

#include "strings.h"
#include <iostream>

using std::cout;

int main() {
    String str1("Hello");
    cout << str1.data() << '\n';
    cout << str1.length() << '\n';
    cout << "----------\n";
    String str2 = "Word";
    cout << str2 << '\n';
    cout << "----------\n";
    String str3 = str1 + str2;
    cout << str3.data() << '\n';
    cout << str3.length() << '\n';
    return 0;
}
AI 代码解读

运行结果:

默认构造函数(Hello)
Hello
5
----------
默认构造函数(Word)
Word
----------
默认构造函数()
HelloWord
9
析构函数(HelloWord)
析构函数(Word)
析构函数(Hello)
AI 代码解读

主程序中的第7行和第11行各自调用一次默认的有参构造函数,第14行是重载的加法运算符中调用了一次无参的构造函数(由于C++编译器的优化,函数返回值没有调用拷贝构造函数)

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

你好,我是AI助理

可以解答问题、推荐解决方案等