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

[]运算符重载

+运算符重载

+=运算符重载

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

String.h:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 
#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:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
 
#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:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 
#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,否则"xxx";
编译出错;operator[] 的non const 版本调用了const 版本的实现,其中使用了static_cast和 const_cast 两种类型转换操作符,可以参考这里;operator+ 调用了operator+= 的实现;只能将流类运算符重载为友元函数,因为第一个参数是流类引用,不是String 类。

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

参考:

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

完善String类([]、 +、 += 运算符重载)、>>和<<运算符重载的更多相关文章

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

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

  2. C++入门经典-例7.10-运算符的重载,重载加号运算符

    1:曾经介绍过string类型的数据,它是C++标准模版库提供的一个类.string类支持使用加号“+”连接两个string对象.但是使用两个string对象相减确实非法的,其中的原理就是C++所提供 ...

  3. String 类实现 以及>> <<流插入/流提取运算符重载

    简单版的String类,旨在说明>> <<重载 #include <iostream> //#include <cstring>//包含char*的字符 ...

  4. string类中运算符重载实现

    C++中预定义的加.减等运算符的操作对象只能是基本的数据类型.如果要在用户自定义的类型对象上应用同样的运算符,就需要通过运算符重载来重新定义其实现,使它能够用于自定义类型执行特定的操作,所以运算符重载 ...

  5. C++重载运算符练习--对people类重载“= =”运算符和“=”运算符

    题目描述 对people类重载“= =”运算符和“=”运算符,“==”运算符判断两个people类对象的id属性是否相等:“=”运算符实现people类对象的赋值操作. 代码如下 #include&l ...

  6. C++编写字符串类CNString,该类有默认构造函数、类的拷贝函数、类的析构函数及运算符重载

    编码实现字符串类CNString,该类有默认构造函数.类的拷贝函数.类的析构函数及运算符重载,需实现以下“=”运算符.“+”运算.“[]”运算符.“<”运算符及“>”运算符及“==”运算符 ...

  7. C++ //多态 //静态多态:函数重载 和 运算符重载 属于静态多态 ,复用函数名 //动态多态:派生类和虚函数实现运行时多态

    1 //多态 2 //静态多态:函数重载 和 运算符重载 属于静态多态 ,复用函数名 3 //动态多态:派生类和虚函数实现运行时多态 4 5 //静态多态和动态多态的区别 6 //静态多态的函数地址早 ...

  8. C++重载流运算符,将存储结构体的vector直接写入文件

    我们知道,当vector很大的时候,如果使用循环的方式将其中的元素写入文件将非常费时,因此有没有办法将vector一次性写入文件呢? 采用流运算符重载的方法可以做到,不仅基本类型的vector可以一次 ...

  9. [置顶] operator overloading(操作符重载,运算符重载)运算符重载,浅拷贝(logical copy) ,vs, 深拷贝(physical copy)

    operator overloading(操作符重载,运算符重载) 所谓重载就是重新赋予新的意义,之前我们已经学过函数重载,函数重载的要求是函数名相同,函数的参数列表不同(个数或者参数类型).操作符重 ...

随机推荐

  1. 蓝屏代码详解(更新WIN7蓝屏代码)

    6位代码含意 0 0x0000 作业完成.  1 0x0001 不正确的函数.  2 0x0002 系统找不到指定的档案.  3 0x0003 系统找不到指定的路径.  4 0x0004 系统无法开启 ...

  2. BZOJ 1032 JSOI 2007 祖码Zuma 区间DP

    题目大意:依照祖玛的玩法(任意选颜色),给出一段区间.问最少用多少个球可以把全部颜色块都消除. 思路:把输入数据依照连续的块处理.保存成颜色和数量.然后用这个来DP.我们知道,一个单独的块须要两个同样 ...

  3. hdu4035之经典慨率DP

    Maze Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) Total Submi ...

  4. CentOS6.5配置网络

    [ CleverCode发表在csdn博客中的原创作品,请勿转载.原创地址:http://blog.csdn.net/clevercode/article/details/46376985] 1 网卡 ...

  5. Integer IntegerCache源码

    先看一段测试结果: /*public static void main(String[] args) { Integer a = 128, b = 128; Integer c = 127, d = ...

  6. OpenShift 容器日志和应用日志分离问题

    一般来说应用日志和容器日志一样输出到console,这样oc logs的时候就能把所有的获取到,但这种模式下输出的日志比较多,问题定位不方便,更多的时候开发人员只想通过应用日志来查看定位问题就够了,所 ...

  7. 从CVPR 2014看计算机视觉领域的最新热点

    编者按:2014年度计算机视觉方向的顶级会议CVPR上月落下帷幕.在这次大会中,微软亚洲研究院共有15篇论文入选.今年的CVPR上有哪些让人眼前一亮的研究,又反映出哪些趋势?来听赴美参加会议的微软亚洲 ...

  8. Hibernate查询语言

    HQL(Hibernate Query Language)查询语言是完全面向对象的查询语言,它提供了更加面向对象的封装,它可以理解如多态.继承和关联的概念.HQL看上去和SQL语句相似,但它却提供了更 ...

  9. asp中将系统货币符号¥改为美国货币符号$的做法

    我们一般用FormatCurrency()函数得到字符串前面都会加上人民币符号¥.但在做一些网站时想把他们变成$. 可以在网面的前面加上一名话就OK了 SetLocale("en-us&qu ...

  10. JS中常用坐标offset、scroll、client的区别

    在IE中scrollWidth:获取对象的滚动宽度scrollHeight: 获取对象的滚动高度.scrollLeft:设置或获取位于对象左边界和窗口中目前可见内容的最左端之间的距离scrollTop ...