1.前言

  最近看了下《C++Primer》,觉得受益匪浅。不过纸上得来终觉浅,觉知此事须躬行。今天看了类类型,书中简单实现了String类,自己以前也学过C++,不过说来惭愧,以前都是用C来写程序,学的C++基本都忘记了,也说明自己以前对C++的理解不够深入。基于这些,觉得有必要动手来写写C++的一些程序了,毕竟C++有很多的功能是C所不具备的。正好看了课本中String类的简单实现,而且string类在C++中的使用频率也很高,了解其内部的实现是很有必要的。所以今天打算写个string类,就当做练手吧。

2.String类的设计

  写类首先是定义类的名字,我们实现的string就叫String吧,以防和标准库中的string类冲突。其次是类中的内部数据,既然是字符串类,必须要把字符串类所代表的字符串保存起来,所以必须定义一个存放这些字符的字符数组或者一个指向字符数组的指针。我是用后者实现,因为这样更为的灵活,不会因为提前定义数组的大小而限制了能存放到数组中的字符个数。为了方便,可以定义字符串的长度,当然也可以不定义,可以在字符数组的末尾存放0来表示字符串的结束,不过每次得到字符串的长度比较麻烦。最后是类对外的接口,根据我们平时使用string类的情况,我们一般会用到接口size(), c_str(),还有就是+,=,>>,<<,+=,[],==等操作符。

  根据前面的分析,可以得到我们要设计的String类中的成员如下所示:

 class String
{
public:
String();
String(const char *);
String(const String &);
String(String &&); //新加的move构造函数 ~String(); String& operator=(const char *);
String& operator=(const String &); bool operator==(const char *);
bool operator==(const String &); char &operator[](int); String operator+(const char *);
String operator+(const char);
String operator+(const String &); String &operator +=(const char *);
String &operator +=(const char);
String &operator +=(const String &); int size(){return _size;}
char *c_str(){return _string;} friend istream &operator>>(istream &cin, String &str);
private:
int _size;
char *_string;
};

3.String类的主要实现

  我们先来说一下构造函数的实现。由于我想实现的String类中存放字符的数组大小是可以根据实际需要存放字符的个数来动态调整的(这样对于存放字符的个数就没有限制,除非内存不够用了),所以必须根据实际存放的字符个数来动态的申请内存空间,代码可以用如下的方式实现:

 String::String(const char *str)
{
if (!str)
{
_size = ;
_string = NULL;
}
else
{
_size = strlen(str);
_string = new char[_size + ];
strcpy(_string, str);
_string[_size] = ;
}
}

  由于构造函数动态申请了内存,所以必须定义析构函数来释放我们申请的内存空间。

 String::~String()
{
if (_string)
delete _string; cout << "~String() call" << endl;
}

  同样,由于我们每个String类都会动态的申请内存空间,所以必须定义拷贝构造函数,否则默认的拷贝构造函数会导致多个String对象共享相同内存空间的问题(深拷贝与浅拷贝的的问题)。代码和前面的构造函数差不多。

 String::String(const String &str)
{
if (!str._size)
{
_size = ;
_string = NULL;
}
else
{
_size = str._size;
_string = new char[_size + ];
strcpy(_string, str._string);
_string[_size] = ;
} }

 

  其它的函数就是对+,=,+=操作符的重载,原理都是一样的,需要重新分配内存空间来适应新的字符串个数的需求,不同的是+的返回类型不需要使用引用。具体代码如下(用+=实现的):

String String::operator+(const String &str)
{
assert(_string && str._string); String str_temp(*this); str_temp += str;
return std::move(str_temp);
}

  由于函数+会返回对象,编译器会默认产生一个临时的对象,这个对象完全是返回对象的拷贝,而返回对象马上就会析构掉,所以如果我们能把返回对象中的字符数组地址拷贝到临时对象中,那么临时对象就可以不用再申请内存了,这样可以提供效率。所以这里我实现了一个move函数( tangzhnju的提醒):

String::String(String && str)
{
_size = str._size;
_string = str._string;
str._string = NULL;
}

  还有我们经常用的是直接对string类进行输出,所以我们必须重载<<,>>操作符,由于输入需要用到String类中的私有成员变量_string,所以应该把输入函数设置为String类的友元函数。而输出可以通过调用c_str函数获得字符数组地址来输出。

istream &operator>>(istream &cin, String &str)
{
const int limit_string_size = ; str._string = new char[limit_string_size]; cin >> setw(limit_string_size) >> str._string;
str._size = strlen(str._string);
return cin;
} ostream &operator<<(ostream &cout, String &str)
{
return cout << str.c_str();
}

  编写这个String类遇到了两个小的问题,一个就是在写+=操作符重载函数的时候,忘记在函数的前面写String::,导致编译器总是包各种莫名的错误,什么参数不对,不能访问内部成员,这个问题完全是自己粗心导致的。另一个问题就是写+操作符重载函数,开始写+函数的时候直接修改了当前的String对象,后来测试发现这是有问题的,因为+应该重新返回一个新的String对象,这个新String对象是当前String对象与传入参数的字符串的和,这个问题完全是自己没有想清楚+与+=的区别,+=才是要修改当前String对象的。

附加:String类实现代码

自己实现简单的string类的更多相关文章

  1. 实现简单的string类

    摘要 实现了一个string类,包括基本的构造.赋值.判断.大小写等. String API Constructors string(); string(const char& ch); st ...

  2. 一个简单的string类,读书看报系列(一)

    对于这个类,写过程序的都知道应该含有的方法是 初始化.销毁.拼接.求长度.清除.判断是否为空等.还有一些操作符重载 一.先看初始化: 可以想到应该有默认构造的的.带有字符串的.带有默认字符的.还有一个 ...

  3. 【c++】简单的string类的几个基本函数

    // string的几个基本函数的实现 #include <iostream> #include <assert.h> #include <string.h> us ...

  4. 【Java】整理关于java的String类,equals函数和比较操作符的区别

    初学 Java 有段时间了,感觉似乎开始入了门,有了点儿感觉但是发现很多困惑和疑问而且均来自于最基础的知识折腾了一阵子又查了查书,终于对 String 这个特殊的对象有了点感悟大家先来看看一段奇怪的程 ...

  5. c++在string类源

    一:回想 (1)c++中的string类是在面试中和笔试中常常考的题目: project代码免费下载 string类的自行实现 (2)c++中的string类和fstream类合起来是处理外部数据的利 ...

  6. 全面深入介绍C++字符串:string类

    http://blog.csdn.net/liuliming3000/article/details/1809385 1 从C到C++ string类 2 string类的构造函数 3 string类 ...

  7. C++标准模板库Stand Template Library(STL)简介与STL string类

    参考<21天学通C++>第15和16章节,在对宏和模板学习之后,开启对C++实现的标准模板类STL进行简介,同时介绍简单的string类.虽然前面对于vector.deque.list等进 ...

  8. C++ char数组和string类简单使用总结

    使用char数组,进行字符串的操作,是c风格的操作方式. string是C++的风格,感觉string本质上就是一个vector<char> 以下代码详细展示了字符串的常见操作 #incl ...

  9. c++string类的简单介绍

    #include "iostream" #include "string" using namespace std; /*@author:浅滩 *family: ...

随机推荐

  1. Web前端面试之HTML

    1. 对WEB标准以及W3C的理解与认识 web标准规范要求,书写标签闭合.小写.不乱嵌套,可提高搜索机器人对网页内容的搜索几率.--- SEO 使用外链css和js脚本,结构与行为.结构与表现分离, ...

  2. 【转】WriteMessage的信息在AutoCAD中命令行中实时显示

    之前程序中有段发送信息到命令行上显示的代码,如下:     ed.WriteMessage("开始标注横断面高程,请稍候!");     但是发现命令行中并不马上显示,代码也明明运 ...

  3. Android课程---序列化与反序列化(转)

    ava序列化与反序列化是什么?为什么需要序列化与反序列化?如何实现Java序列化与反序列化?本文围绕这些问题进行了探讨. 1.Java序列化与反序列化 Java序列化是指把Java对象转换为字节序列的 ...

  4. Python读写文件

    Python读写文件1.open使用open打开文件后一定要记得调用文件对象的close()方法.比如可以用try/finally语句来确保最后能关闭文件. file_object = open('t ...

  5. 并联机构逆运动学用MapleSim符号来解决

    在多体机械中,平台的运动学分析(运动学问题)可以分为两类:正向运动学问题和逆向运动学问题.所谓正向运动学是指研究机构中一点(例如,机械手臂上终端操作机构或由并联机械操纵器支持的平台的中心)在空间中的位 ...

  6. ubuntu下 编译安装swftools

    1.下载:http://www.swftools.org/download.html2.安装: tar -zvxf swftools-0.x.x.tar cd swftools-0.x.x ./con ...

  7. ruby 访问新浪微博API post方式和get方式

    require 'net/https' require 'uri' def post_api(api, args) uri = URI.parse api http = Net::HTTP.new(u ...

  8. C#_闭包陷阱

    如果匿名方法(Lambda表达式)引用了某个局部变量,编译器就会自动将该引用提升到该闭包对象中. 即将for循环中的变量i修改成了引用闭包对象的公共变量i.这样一来,即使代码执行后离开了原局部变量i的 ...

  9. Principles of measurement of sound intensity

    Introduction In accordance with the definition of instantaneous sound intensity as the product of th ...

  10. iOS并发编程笔记【转】

    线程 使用Instruments的CPU strategy view查看代码如何在多核CPU中执行.创建线程可以使用POSIX 线程API,或者NSThread(封装POSIX 线程API).下面是并 ...