class String from C++_OOP_base1_houjie
string.h
#ifndef __MYSTRING__
#define __MYSTRING__
using namespace std;
class String
{
public:
String (const char*); // const: 不修改该指针; 函数会修改目的端对象的成员变量,所以
// *Big Three*
// **class with pointer members必须有copy ctor(1)和copy op=(2)**;
// **default copy op=会将对象a的数据(pointer) copy到对象b中(pointer),即将b的指针指向a所指的字符数组; 然而我们希望赋值之后两个字符数组的内容相同,而现在只有**
// 1. 拷贝构造(copy constructor): 接受的是自己这种东西
String (const String& str); // 注意默认参数不能同时出现在声明和定义中
// 2. 拷贝赋值(copy assignment operator): 接受的是自己这种东西
String& operator= (const String& str);
// 3. 析构函数(destructor):String对象死亡时会自动调用析构
~String();
char* get_c_str() const { return m_data; } // get c-like string; default inline
private:
char* m_data; // 放一个指针指向不固定大小的字符数组; 而非直接使用字符数组;
// 对象内只有这个指针,字符数组不属于对象内,是被动态分配到其他地方的;
};
// String::function(...)...
#include <string.h>
inline String::String (const char* cstr = 0)
{
if (cstr) { // class有pointer member时多半需要动态内存分配
m_data = new char[strlen(cstr) + 1]; // return the addr of char array; strlen ignore '\0';
strcpy(m_data, cstr);
} else { // 空指针的时候分配一个'/0'即可
m_data = new char[1]; // char array
*m_data = '\0';
}
}
inline String::~String()
{
// 如果动态内存分配了,就需要在对象死亡之前调用析构函数的时候释放掉内存;
delete[] m_data; // clean up memory to avoid leaks
}
inline String::String (const String& str)
{
m_data = new char[strlen(str.m_data + 1)];
strcpy(m_data, str.m_data);
}
inline String& String::operator= (const String& str) // 注意这里的&是reference,要放在typename的后面;
{
// **一定要在拷贝赋值函数中检测是否自我赋值(self assignment)**
// 自我赋值的时候两个指针指向同一块字符数组,delete[]之后就寄了;
if (this == &str) // 注意这里的&是取地址 address of,要放在object的前面; 得到一个指针;
return *this;
// 清空左值-创建空间-复制右值
delete[] m_data;
m_data = new char[strlen(str.m_data) + 1];
strcpy(m_data, str.m_data);
return *this; // 允许连续赋值
// 直接传value出去,不用管接收方使用value还是引用
}
// Global-function(...)...
#include <iostream>
// << 要使用非成员函数,无法直接访问m_data;
ostream& operator<< (ostream& os, const String& str)
{
os << str.get_c_str(); // 内置的cout可以根据指针输出字符串
return os;
}
#endif
string-test.cpp
#include <iostream>
#include "string.h"
using namespace std;
int main()
{
String s1; // 不能写作String s1(); 这是一个function
String s2("hello");
String* p = new String("hello"); // p是一个新指针,指向字符数组的那个指针(该指针指向另一个指针)
delete p; // 这三个都会调用析构函数释放字符串的指针,而这个指针需要额外释放指针的指针;
String s3(s1); // 拷贝构造
// 等价于String s3 = s1; 把s1赋值到s3, 且s3是新创建的,所以调用拷贝构造;
cout << s3 << endl;
s3 = s2; // 拷贝赋值
cout << s3 << endl;
}