自实现 myString 类主要目的是剖析系统内部的 string 类的一些实现方法以及加强对类封装、运算符重载等特性的掌握。其中包含了几项非常重要的功能实现。
- 使用构造器创建对象。
- 拷贝构造器创建对象。
- 赋值运算符重载构造对象。
- []运算符重载构造对象数组。
- ==运算符重载判断对象是否相等。
- +运算符重载实现对象相加。
- >> << 流输入输出运算符实现打印和输入。
具体的实现代码分三个部分,一个 MyString.h 文件,包含类的声明和结构。一个 MyString.cpp 文件,包含类的成员及友元函数实现。最终是一个 main.cpp 来测试我们自己的 MyString 类是否可以正常使用。
【myString.h】
#pragma once
#include <iostream>
class CMyString
{
public:
// 构造器
CMyString(char* str = NULL);
// 拷贝构造器原型,another为传递进来的同类对象
CMyString(const CMyString & another);
// 赋值运算符重载,系统会提供默认,但同样是等位拷贝
CMyString& operator=(const CMyString & another);
// []运算符重载
char operator[](int idx);
// ==运算符重载
bool operator==(const CMyString& another);
// + 运算符重载
CMyString operator+(const CMyString& another);
// 流输入输出
friend std::ostream& operator<<(std::ostream& os, CMyString& another);
friend std::istream& operator<<(std::istream& is, CMyString& another);
~CMyString(void);
char* c_str();
private:
char* m_str;
};
【myString.cpp】
#include "MyString.h"
#include <cstring>
CMyString::CMyString(char* str)
{
if (str)
{
int len = strlen(str);
m_str = new char[len + 1];
strcpy_s(m_str, len + 1, str);
}
else
{
m_str = new char[1];
*m_str = '\0';
}
}
CMyString::CMyString(const CMyString & another)
{
// 浅拷贝,等位拷贝,会造成 double free
// 这样操作会导致 m_str 和 another.m_str 指向同一块堆内存
// 析构时会造成 delete 了同一块内存
// m_str = another.m_str;
// 深拷贝,根据another.m_str的长度给对象new一块内存使双方不冲突
int len = strlen(another.m_str);
m_str = new char[len + 1];
strcpy_s(m_str, len + 1, another.m_str);
}
CMyString& CMyString::operator=(const CMyString & another)
{
if (this == &another)
{
// 解决 s6 = s6 会导致崩溃的问题
return *this;
}
delete [] m_str;
int len = strlen(another.m_str);
m_str = new char[len + 1];
strcpy_s(m_str, len + 1, another.m_str);
return *this;
}
char CMyString::operator[](int idx)
{
return m_str[idx];
}
bool CMyString::operator==(const CMyString& another)
{
if (strcmp(this->m_str, another.m_str) == 0)
return true;
else
return false;
}
CMyString CMyString::operator+(const CMyString& another)
{
int len = 0;
len = strlen(this->m_str);
len += strlen(another.m_str);
CMyString tmp;
delete [] tmp.m_str;
tmp.m_str = new char[len + 1];
memset(tmp.m_str, 0, len + 1);
strcat_s(tmp.m_str, len + 1, this->m_str);
strcat_s(tmp.m_str, len + 1, another.m_str);
return tmp;
}
std::ostream& operator<<(std::ostream& os, CMyString& another)
{
os << another.m_str;
return os;
}
std::istream& operator<<(std::istream& is, CMyString& another)
{
// 先删除了原来保存的数据
delete [] another.m_str;
char buffer[BUFSIZ];
is.getline(buffer, BUFSIZ);
int length = strlen(buffer);
another.m_str = new char[length + 1];
strcpy_s(another.m_str, length + 1, buffer);
return is;
}
CMyString::~CMyString(void)
{
std::cout << "delete [] m_str : " << m_str << std::endl;
delete [] m_str;
}
char* CMyString::c_str()
{
return m_str;
}
【main.cpp】
#include <iostream>
#include "MyString.h"
using namespace std;
int main(int argc, char* argv[])
{
// 构造函数,无参数
CMyString s;
cout << s.c_str() << endl;
// 构造函数,有参数
CMyString s1("china");
cout << s1.c_str() << endl;
// 类型转化函数
CMyString s2 = "china";
cout << s2.c_str() << endl;
/*
以上均是调用构造器来创建的
*/
// 拷贝构造器
CMyString s3(s2);
cout << s3.c_str() << endl;
// 同上
CMyString s4 = s3;
cout << s4.c_str() << endl;
// 赋值,=号运算符重载
CMyString s5;
// 等同于 s5.operator= (s4);
s5 = s4;
// 同上 相当于s5.operator=(s4.operator=(s3));
s5 = s4 = s3;
cout << s5.c_str() << endl;
CMyString s6("china");
// 这样操作会进入=号运算符重载的函数内
// 但刚进入后 s6 就被 delete 了
// 如果继续后面的操作将会导致访问违规内存而报错
// 个别系统环境下可能不报错,带不代表就是正确的
s6 = s6;
cout << s6.c_str() << endl;
// []运算符重载
cout << s6[2] << endl;
// ==运算符重载
if (s5 == s6) cout << "s5 == s6" << endl;
// + 运算符重载
CMyString s7 = s6 + s5;
cout << s7.c_str() << endl;
cout << s7 << endl;
getchar();
return 0;
}