从零开始学C++之运算符重载(三):完善String类([]、 +、 += 运算符重载)、>>和<<运算符重载

在前面文章中使用过几次String类的例子,现在多重载几个运算符,更加完善一下,并且重载流类运算符。

[]运算符重载

+运算符重载

+=运算符重载

<<运算符重载 >>运算符重载

String.h:

#ifndef _STRING_H_
#define _STRING_H_
#include <iostream>
using namespace std;

class String
{
public:
    String(const char *str = "");
    String(const String &other);
    String &operator=(const String &other);
    String &operator=(const char *str);

    bool operator!() const;
    char &operator[](unsigned int index);
    const char &operator[](unsigned int index) const;

    friend String operator+(const String &s1, const String &s2);
    String &operator+=(const String &other);

    friend ostream &operator<<(ostream &os, const String &str);
    friend istream &operator>>(istream &is, String &str);
    ~String(void);

    void Display() const;
    int Length() const;
    bool IsEmpty() const;

private:
    String &Assign(const char *str);
    char *AllocAndCpy(const char *str);
    char *str_;
};

#endif // _STRING_H_

String.cpp:

#pragma warning(disable:4996)
#include "String.h"
#include <string.h>
//#include <iostream>
//using namespace std;

String::String(const char *str)
{
    str_ = AllocAndCpy(str);
}

String::String(const String &other)
{
    str_ = AllocAndCpy(other.str_);
}

String &String::operator=(const String &other)
{
    if (this == &other)
        return *this;

    return Assign(other.str_);
}

String &String::operator=(const char *str)
{
    return Assign(str);
}

String &String::Assign(const char *str)
{
    delete[] str_;
    str_ = AllocAndCpy(str);
    return *this;
}

bool String::operator!() const
{
    return strlen(str_) != 0;
}

char &String::operator[](unsigned int index)
{
    //return str_[index];
    //non const 版本调用 const版本

    return const_cast<char &>(static_cast<const String &>(*this)[index]);
}

const char &String::operator[](unsigned int index) const
{
    return str_[index];
}

String::~String()
{
    delete[] str_;
}

char *String::AllocAndCpy(const char *str)
{
    int len = strlen(str) + 1;
    char *newstr = new char[len];
    memset(newstr, 0, len);
    strcpy(newstr, str);

    return newstr;
}

void String::Display() const
{
    cout << str_ << endl;
}

int String::Length() const
{
    return strlen(str_);
}

bool String::IsEmpty() const
{
    return Length() == 0;
}

String operator+(const String &s1, const String &s2)
{
    //int len = strlen(s1.str_) + strlen(s2.str_) + 1;
    //char* newstr = new char[len];
    //memset(newstr, 0, len);
    //strcpy(newstr, s1.str_);
    //strcat(newstr, s2.str_);
    //
    //String tmp(newstr);
    //delete newstr;
    String str = s1;
    str += s2;
    return str;
}

String &String::operator+=(const String &other)
{
    int len = strlen(str_) + strlen(other.str_) + 1;
    char *newstr = new char[len];
    memset(newstr, 0, len);
    strcpy(newstr, str_);
    strcat(newstr, other.str_);

    delete[] str_;

    str_ = newstr;
    return *this;
}

ostream &operator<<(ostream &os, const String &str)
{
    os << str.str_;
    return os;
}

istream &operator>>(istream &is, String &str)
{
    char tmp[1024];
    cin >> tmp;
    str = tmp;
    return is;
}

main.cpp:

#include "String.h"
#include <iostream>
using namespace std;

int main(void)
{
    String s1("abcdefg");

    char ch = s1[2];
    cout << ch << endl;

    s1[2] = 'A';
    s1.Display();

    const String s2("xyzabc");
    ch = s2[2];
    //s2[2] = 'M'; Error
    s2.Display();


    String s3 = "xxx";
    String s4 = "yyy";

    String s5 = s3 + s4;
    s5.Display();

    String s6 = "aaa" + s3 + "sdfadfa" + "xxxx";
    s6.Display();

    s3 += s4;
    s3.Display();

    cout << s3 << endl;

    String s7;
    cin >> s7;
    cout << s7 << endl;

if (!s7.IsEmpty())
cout<<s7.Length()<<endl;

    return 0;
}

需要注意的是,不能将String类的构造函数声明为explicit,否则    String s3 = "xxx"; 编译出错;operator[] 的non const 版本调用了const 版本的实现,其中使用了static_cast和 const_cast 两种类型转换操作符,可以参考这里;operator+ 调用了operator+= 的实现;只能将流类运算符重载为友元函数,因为第一个参数是流类引用,不是String 类。

通过实现这样一个字符串类,我们可以熟悉基本的内存管理与拷贝控制。

参考:

C++ primer 第四版 Effective C++ 3rd C++编程规范

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java技术学习之道

Java日志框架:logback详解

1645
来自专栏每日一篇技术文章

Swift3.0 - 枚举

642
来自专栏Coco的专栏

javascript中函数声明和函数表达式浅析

1489
来自专栏刘望舒

Android网络编程(十)Retrofit2后篇[注解]

前言 在上一篇Android网络编程(九)Retrofit2前篇[基本使用]中我们了解了Retrofit的最基本的GET方式访问网络的写法以及请求参数的简单介绍...

1796
来自专栏Linyb极客之路

Java虚拟机:Java内存区域及对象

为以后写文章考虑,也为巩固自己的知识和一些基本概念,这里要理清楚几个计算机中的概念。

862
来自专栏小白客

Python基础学习-函数

一:定义函数: ① 函数是带名字的代码块,用于完成具体的工作。 ② 函数使用关键字def来定义,最后,定义以冒号结尾。 ③ 每个函数后面都应紧跟一个文档字符串,...

3658
来自专栏小樱的经验随笔

C/C++中peek函数的原理及应用

C++中的peek函数   该调用形式为cin.peek() 其返回值是一个char型的字符,其返回值是指针指向的当前字符,但它只是观测,指针仍停留在当前位置,...

2815
来自专栏更流畅、简洁的软件开发方式

【自然框架】——页面基类与设计模式(二) 模板模式

前篇:【自然框架】——页面基类与设计模式(一)桥接模式 桥接模式的补充:(下面的一段是桥接模式里后补充的一段,桥接模式的一个小结) 什么是交接模式?引用《大话设...

23510
来自专栏开心的学习之路

JavaScript概览

近日的项目需要用JavaScript完成,于是决定通读《JavaScript高级程序设计第三版》,书是2012年的,比较老了,但是可以用来快速了解JavaScr...

2884
来自专栏微信公众号:Java团长

Java虚拟机:Java内存区域及对象

为以后写文章考虑,也为巩固自己的知识和一些基本概念,这里要理清楚几个计算机中的概念。

952

扫码关注云+社区