MyString类的实现--基础中的基础C语言

MyString 类是学习 C++ 的过程当中一个很重要的例子,涉及到面向对象的封装、堆内存申请和释放、函数的重载以及 C++ 的 “Big Three”。本例子重点在于复习和理解上述的 C++ 特性,实现的功能并很少。c++

MyString 类的 Header

MyString 的声明中包含了一个带指针的 C++ 类应有的函数,而且包含了一些经常使用的功能。其中终点讨论一下用 friend 关键字修饰的两个函数,它们是用来提供 ostream 的输出的。声明为 friend 是为了使 ostream 的对象(例如 cout)能够访问到 MyString 的成员。而这两个函数不声明为内部方法的缘由是咱们通常写输入输出语句都是将流对象写在前,若是声明成了成员函数则调用的时候要写成这样:编程

MyString str; str.operator<<(cout);

这看起来至关怪异,因此咱们但愿写成 cout << str 这样。这句实际上就是 cout 对象调用重载的运算符,也能够写在实例化 cout 对象的类 ostream 里,可是 ostream 通常来讲咱们并不会去改动这个文件,因此写了一个全局函数来将 ostream 和 MyString 联系起来。函数

class MyString { friend std::ostream &operator<<(std::ostream &os, const MyString &str); friend std::ostream &operator>>(std::ostream &os, MyString &str); public: MyString(const char *cstr = nullptr); // Big Three MyString(const MyString &str); MyString &operator=(const MyString &str); ~MyString(); char *get_c_str() const { return m_data; } // operator reload MyString &operator+(const MyString &str); bool operator==(const MyString &str); size_t length() const; private: char *m_data; };

 

C++ 的构造函数和 Big Three

C++ 的 Big Three 包括拷贝赋值、拷贝构造和析构函数。Big Three 主要针对带有指针的类,类中的指针通常指向类所管理的一些资源,多是该类本身申请的内存或者建立的某种对象。类维护着这些资源,负责它们的生老病死——资源的建立、使用和销毁。学习

一个类中若是带有着指针,那么必需要本身重写有拷贝构造和拷贝赋值函数。若是不本身重写,那么会采起默认的行为,即逐位拷贝。采起逐位拷贝的对象内部的指针也被拷贝过去,称为浅拷贝。咱们但愿拷贝一个对象,其管理的资源也一并拷贝一份,称为深拷贝。为了实现深拷贝,重写的拷贝赋值、拷贝构造函数中应实现资源复制的行为。而在对象生命周期结束后,其管理的资源也应该关闭或者销毁,故也须要重写析构函数。this

C++ 的这三个函数紧密地联系在了一块儿,具体体现为逻辑上若是须要重写其中任何一个函数,那么另外两个函数也应该被重写spa

inline MyString::MyString(const char *cstr = nullptr) { if (cstr) { m_data = new char[strlen(cstr) + 1]; strcpy(m_data, cstr); } else { m_data = new char[1]; *m_data = '\0'; } } inline MyString::~MyString() { delete[] m_data; } inline MyString::MyString(const MyString &str) { m_data = new char[strlen(str.m_data) + 1]; strcpy(m_data, str.m_data); } inline MyString &MyString::operator=(const MyString &str) { if (this == &str) return *this; delete[] m_data; m_data = nullptr; m_data = new char[strlen(str.m_data) + 1]; strcpy(m_data, str.m_data); return *this; }

 

在上面的实现中,有两个值得注意的地方,一个是在拷贝赋值运算符重载中的自赋值检查,在拷贝赋值运算符函数中,若是不进行检查,按照逻辑来讲,会释放被赋值对象的资源,若是是同一个对象的自我赋值,则会产生严重的后果:字符串资源被删除,两个对象指向被回收了的内存,当访问这个字符串时会出现不可预料的后果。可见,防护式编程不只要求程序对黑客行为的输入的那些很离谱的数据作防护,还要对用户可能出现的错误进行防护。.net

另一个值得注意的地方就是重载的等于操做符,用户在使用的时候有时可能会对字符串连续赋值,就像使用 cout 连续输出同样,这种相似于函数的链式调用。实现的时候只要返回对象的引用就能够了。指针

输入输出运算符重载

除了链式调用须要返回对象引用的这个主意点外,输入输出函数的第二个参数的 const 属性也应该主意的。具体来讲输出函数的第二个参数不会被改变,咱们应该将它声明为 const 的;而输入函数的第二个对象正是咱们但愿改变的对象,但愿将数据输入到这个对象中,它应该是非 const 引用。code

std::ostream &operator<<(std::ostream &os, const MyString &str) { os << str.m_data; return os; } std::ostream &operator>>(std::ostream &os, MyString &str) { os >> str.m_data; return os; }

 

至此一个很是简单的 C++ MyString 类已经实现完成了,在 STL 中,string 类的实现更加复杂,包括了正则在内的高级功能。这个例子仅仅为了学习 C++ 的一些特性,还不够深刻,但愿将来能专门研究一下 string 的实现。对象

--------------------- 本文来自 ProJ7-Jeffy 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/u013040821/article/details/80455108?utm_source=copy 

相关文章
相关标签/搜索