class MyString{
public:
MyString(char* = nullptr);
~MyString();
MyString& operator=(const MyString &);
MyString(const MyString &);
bool operator==(const MyString &);
void showstring();
private:
char *m_data;
};
#include "MyString.h"
MyString::MyString(char *c){
if (c)
{
m_data = new char[strlen(c) + 1];
strcpy(m_data, c);
}
else
{
m_data = new char[1];
*m_data = '\0';
}
}
MyString::~MyString(){
delete[] m_data;
}
MyString& MyString::operator=(const MyString &fuzhi){
if (this==&fuzhi) //避免自我复制
{
return *this;
}
delete[] m_data;
m_data = NULL;
m_data = new char[strlen(fuzhi.m_data) + 1];
strcpy(m_data, fuzhi.m_data);
return *this;
}
MyString::MyString(const MyString ©){
m_data = new char[strlen(copy.m_data) + 1];
strcpy(m_data, copy.m_data);
}
bool MyString::operator==(const MyString &dengyu){
return strcmp(m_data, dengyu.m_data) == 0;
}
void MyString::showstring(){
cout << this->m_data << endl;
}
拷贝构造函数会在以下三种情况下被调用:
1).当用类的一个对象去初始化该类的另一个对象时。
2).如果函数的形参是类的对象,调用该函数,将对象作为函数实参传递给函数的形参时。
3).如果函数的返回值是类的对象,函数执行完成,将返回值返回时。
拷贝构造函数的参数必须为引用
复制构造函数,本身也是一个函数,如果你给它定义的参数,是一个类型,而不是一个类型的引用,它会首先调用该类型的复制构造函数,重新构造一个新的实例,然而此时的复制构造函数是以值传递的,又要调用复制构造函数,周而复始,一直循环下去了。。。
赋值构造函数参数既可以为引用,也可以为值传递,值传递会多一次拷贝。因此建议赋值构造函数建议也写为引用类型
复制构造函数的注意事项:
类String的赋值函数比构造函数复杂得多,分四步实现:
(1)第一步,检查自赋值。你可能会认为多此一举,难道有人会愚蠢到写出 a = a 这样的自赋值语句!的确不会。但是间接的自赋值仍有可能出现,例如
(2)第二步,用delete释放原有的内存资源。如果现在不释放,以后就没机会了,将造成内存泄露。
(3)第三步,分配新的内存资源,并复制字符串。注意函数strlen返回的是有效字符串长度,不包含结束符‘\0’。函数strcpy则连‘\0’一起复制。
(4)第四步,返回本对象的引用,目的是为了实现象 a = b = c 这样的链式表达。注意不要将 return *this 错写成 return this 。
如果构造函数中存在动态内存分配,则必须定义拷贝构造函数。否则,会出现“指针悬挂问题”。
class A{
private:
int *p;
public:
A(){p = new int(3);}
}
这种情况下,必须最定义拷贝构造函数。否则会造成两个对象的成员指向同一地址。