Class myString
{
public:
myString(const char *value);
~myString();
private:
char *data;
} ;
最简单的类myString,但是值得注意的是它里面有个指针成员char * data。
先来写清楚这个构造函数——
myString::myString(const char *value)
{
if (value)
{
data = new[strlen(data)+1];
strcpy(data, value);
}
else
{
data = new[1];
data[0] = '/0';
}
}
myString::~myString()
{
delete [] data;
}
好,实例化myString,
myString a("phoebe"); // a.data = "phoebe/0"
myString b("bear"); // b.data = "bear/0"
此时,如果有代码,
a = b;
那么会怎么样呢?
因为myString类没有拷贝构造函数,也没有赋值函数,所以编译器默认的操作是执行“位拷贝”,位拷贝的结果是:
a = b; 等价于 a.data = b.data;
这会造成几种错误:
(1) a从前那块内存没有人去管了,MLK error here!
(2) 如果程序中销毁a和b实例,那么b.data这块内存被double delete了!
(3) 如果a和b的生存空间不同,那么销毁a和b其中的一个,将导致b.data的空间被释放,另一个指针还依然指向这块儿内存呢!
因此,得出结论:只要类里面有指针,为避免此类MLK,就需要自己给它写个拷贝构造函数和赋值函数!
ok,来写下myString的拷贝构造函数——
非常简单,其实无非就是从新开辟了块内存,来避免多对象的成员指针指向同一块内存的问题。
myString::myString(const myString & thatString)
{
data = new char[strlen(thatString.data)+1];
strcpy(data, thatString.data);
}
这个是赋值函数——
相比较拷贝构造函数,想想便知道,赋值嘛,如果让自己赋给自己,那就不用赋了,除此之外,还要考虑以前的对象已经初始化过的情况,所以要先把以前的灭掉,再给它新生。
myString & myString::operator = (const myString & that)
{
if (this == &that)
return this;
delete [] data;
data = new char[strlen(that.data) + 1];
strcpy(data, that.data);
return *this;
}