一、拷贝构造,拷贝复制
如果创建了带指针的类,那么一定要自己写拷贝函数,不能用编译器中的,因为编译器将指针复制,两个指针仍然指向同一个地址,不是真正意义上的拷贝。
一般字符串的设计
让字符串里面拥有一根指针,在需要内存时才去创建另外一个空间来放字符本身,字符有大有小,有种动态的感觉。
所以字符串的data应该是一个指针,指向字符。
1.String类的设计
class String
{
public:
String(const char* cstr = 0); //构造函数,传进一根指向char类型指针,默认给他0
String(const String& str); //拷贝构造函数 -> 1
String& operator= (const String& str); //操作符重载,拷贝赋值函数 -> 2
~String(); //析构函数 -> 3
char* get_c_str() const { return m_data; } //一般的成员函数,由于没有改变值,要加const
private:
char* m_data;
};
Big Three 三个特殊函数
拷贝构造函数:是一个构造函数,因为名称和类的名称相同,但是接收的参数是自己这种类型,所以叫拷贝构造函数
拷贝赋值函数:=右边也是自己
析构函数:以这个类做出的对象,当他死亡时,(离开作用域等,大括号是作用域),析构函数会被调用
几个函数的具体设计
1.构造函数
inline
String::String(const char* cstr = 0)//拷贝构造函数,默认初始值为0,即若没有则为0
{
if (cstr) //传进来的不为空
{
m_data = new char[strlen(cstr) + 1]; //分配的空间有多大呢?传进来的长度+1(结束符)
strcpy(m_data, cstr); //把传进来的值拷贝到刚刚分配的空间
}
else //未指定初值
{
m_data = new char[1]; //分配一块内存
*m_data = '\0'; //准备一个字符放结束符
}
}
调用示例
{
String s1();
String s2("hello");
//大括号是作用域哦!!!
String* p = new String("hello");
delete p;
}
2.析构函数
对象死亡的前一刻,释放内存,因为之前动态分配了一块内存,需要释放,不然会造成内存泄漏。
inline
String::~String()//析构函数
{
delete[] m_data;
}
一个带指针的类必须有拷贝构造和拷贝赋值函数!!!
原因:例如 b=a ,a和b中的data均为指向字符串的地址,把a中的data赋值给b,那么a和b指向同一块。(浅拷贝)
然而我们希望的是赋值之后,两端需要分别有相同内容(深拷贝)。
浅拷贝后,b端的内容没有指针指着,会造成内存泄漏。
3.拷贝构造函数(深拷贝)
此处,直接取另一个object的private data,因为兄弟之间互为friend
inline
String ::String(const String& str)
{
m_data = new char [ strlen(str.m_data) + 1 ];//分配足够的空间容纳蓝本,然后把内容拷贝过去
strcpy(m_data,str.m_data);
}
{
String s1("hello");//下面两句话的意思完全相同,写法却不一样
String s2(s1);//以s1为蓝本(初值)创建一个s2
String s2=s1;//把s1赋值到s2身上,注意此时s2也是一个新创建出的对象,需要调用构造函数
}
4.拷贝赋值函数
把右边的赋值给左边,先把左边清空,再创建出和右边一样大的空间,最后将右边的拷贝到左边
例如 s2=s1,赋值操作符作用在s2身上
(1)检测自我赋值,功力深厚,大家风范
检测是不是自己赋给自己,如果是,则后面都不做了,直接返回。
必须写!!!若不写,释放本身内存空间后,要去看右边长度,然而右边已经不存在了。
自我赋值不仅为了效率,也为了正确性!
(2)s2先杀掉自己(delete)
(3)分配内存
(4)把字符串拷贝进去
inline
String& String::operator=(const String& str)//拷贝赋值,这里有个隐藏的第一参数this
{
if (this == &str)//&在对象前面故这里是取地址,得到的是一根指针!!!不是引用(&在类型后面)
return *this;
delete[] m_data;
m_data = new char[strlen(str.m_data) + 1];
strcpy(m_data, str.m_data);
return *this;
}