2 下面两个才是赋值
MyString b("world");
MyString c;
b = a;
c = a;
这个时候,你需要先删除之前的data数据,考虑到有的时候参数为0,所以就定义一个参数为0的构造函数,或者将上面的构造函数写成MyString::MyString(const char* value = NULL)的缺省参数的形式。
3 拷贝构造函数的时候,不需要删除data,因为拷贝构造函数的时候,this->data肯定没有申请空间,删除会引起错误。
4 上面代码其实有二个错误,就是应该申请的空间为strlen(data)+1,最后一位'\0';
我在cygwin 下面运行是没问题的,估计是侥幸,但是 vs里面运行就会崩溃。
另外,大家可以练习怎么写这个函数,面试经常会问到的。真正的理解,需要一个过程,主要很多细节:要判断是否相等,要注意什么时候可以删除data,什么时候不可以, 要注意new [] 和delete[] 的对应。
条款12: 尽量使用初始化而不要在构造函数里赋值
书上介绍的很清楚了,我这里主要总结一下、
初始化的好处:
1 const 和引用必须使用初始化,而不能用赋值。
2 效率高。
初始化的流程,就一步,将类成员初始化。
而构造函数内赋值则有两步:第一,调用默认构造函数,第二,调用赋值构造函数。
类的构造函数的本质上是函数,函数就有形参和实参。
例如
[cpp]
class A
{
pulic:
A(B &bInput);
private:
B b;
}
A::A(B &bInput)
{
b = bInput;
}
class A
{
pulic:
A(B &bInput);
private:
B b;
}
A::A(B &bInput)
{
b = bInput;
}
它的流程是什么呢?先调用B()生成b,然后在调用operator = 赋值函数,效率当然无法保证了。这也是第一条的原因,如果是 const或者引用则等于是声明了一下,而没有初始化,那么编译的时候肯定报错。
条款13: 初始化列表中成员列出的顺序和它们在类中声明的顺序相同
举个简单例子:
[cpp]
#include
using namespace std;
class A
{
public:
A(int value);
void print();
private:
int i;
int j;
};
A::A(int value):j(value),i(j)
{
}
void A::print()
{
cout< }
int main()
{
A a(10);
a.print();
}
#include
using namespace std;
class A
{
public:
A(int value);
void print();
private:
int i;
int j;
};
A::A(int value):j(value),i(j)
{
}
void A::print()
{
cout< }
int main()
{
A a(10);
a.print();
}
这个输出的结果是什么?
有些人以为是10 10
我电脑上的结果是
2281060 10
第一个数是随机数,因为执行的顺序是j(i) 然后才是j(10)
条款14: 确定基类有虚析构函数
我之前有篇文章专门将这个,大家可以看看
http://blog.csdn.net/mlkiller/article/details/8884321
这里就不展开了。
条款15: 让operator=返回*this的引用
刚才在写前面的例子,重载符号<<和=的时候,我还想返回值怎么去写。
<<符号是和=都是二元操作符,但是后面跟的参数不一样,<<跟了两个参数,流对象和操作对象,它最后返回流对象。
而=只有自己,它的返回值呢应该是这个对象本身,我就在纠结&引用怎么返回,它和this指针之间什么关系。
等知道答案的时候,还是有些疑惑*this和&引用相等么?看个例子
[cpp]
int p = 1;
int *q = &p;
int &t = p;
int &s = *q;
int p = 1;
int *q = &p;
int &t = p;
int &s = *q;
你看到引用本身怎么用指针初始化。
关于文中返回const类型,我没有搞得太清楚,时间比较晚了,以后弄明白在写进来。