effective C++条款04
首先放上一段存在多义性的代码:
class point {
public:
point() {}
point(int xx = 0, int yy = 0):x(xx),y(yy){}
private:
int x, y;
};
int main() {
point p;
system("pause");
return 0;
}
显然编译时报错,因为创建对象p时,p不知道该调用哪一个构造函数,这是因为point(int xx = 0, int yy = 0)
带默认形参,和point()
在重载的时候产生了多义性。
不要混淆初始化和赋值的概念
再看一段程序:
class point {
friend class line;
public:
point(){}
point(int xx, int yy):x(xx),y(yy){}
point(const point &p) :x(p.x), y(p.y) {};
private:
int x, y;
};
class line {
public:
line(const point &xp1, const point &xp2);//line类(组合类)的构造函数,初始化line类对象的数据成员;形参xp1、xp2表示point类中已有的对象
line(const line &l) :p1(l.p1), p2(l.p2), length(l.length) {};//line类(组合类)的复构函数
double getlength() { return length; }
private:
point p1, p2;//line类中有3个数据成员:point类的两个对象和length
double length;
};
//line类(组合类)的构造函数的实现
line::line(const point &xp1, const point &xp2)//:p1(xp1),p2(xp2)
{
p1 = xp1;//这些都是赋值
p2 = xp2;//不是初始化!!!
double x = static_cast<double>(p1.x - p2.x);
double y = static_cast<double>(p1.y - p2.y);
length = sqrt(x*x + y*y);
}
注意:在line类(组合类)的构造函数本体内,p1、p2都不是被初始化,而是被赋值,而length是内置类型的,不用讨论这些。C++规定,对象成员变量的初始化发生在进入构造函数本体之前。所以point类的两个对象p1、p2其实在进入line类(组合类)的构造函数本体之前就被初始化了(很简单,程序里加断点就会发现在进入line类(组合类)的构造函数本体之前,就已经调用了2次point类的默认构造函数!!!)。
这样导致一个问题:首先调用point类的默认构造函数为p1、p2设初值,然后立刻对它们赋予新值,point类的默认构造函数的一切作用就白费了,效率太低。
接下来,把line类(组合类)的构造函数进行如下修改:
line::line(const point &xp1, const point &xp2):p1(xp1),p2(xp2),length(0)
{
double x = static_cast<double>(p1.x - p2.x);
double y = static_cast<double>(p1.y - p2.y);
length = sqrt(x*x + y*y);
}
显然,用了初始化列表后,再单步调试时会发现,在初始化列表中直接调用了2次point类的复构函数,完成了p1、p2的构造(初始化),这样效率就高多了。
最后一点就是,如果成员变量是const或者引用,它们一定需要初值,不能被赋值,因此必须在初始化列表中初始化。
综上所述,构造函数最好使用初始化列表,而不要在构造函数本体内使用赋值操作。而且类中的成员变量总是以其声明次序被初始化,与初始化列表中的顺序无关。
完整代码如下:
//line类包括point类的两个对象p1、p2作为数据成员,line类具有计算线段长度的功能,在line类的构造函数中实现
#include<iostream>
#include<cmath>
using namespace std;
class point {
friend class line;
public:
point(){}
point(int xx, int yy):x(xx),y(yy){}
point(const point &p) :x(p.x), y(p.y) {};
private:
int x, y;
};
class line {
public:
line(const point &xp1, const point &xp2);//line类(组合类)的构造函数,初始化line类对象的数据成员;形参xp1、xp2表示point类中已有的对象
line(const line &l) :p1(l.p1), p2(l.p2), length(l.length) {};//line类(组合类)的复构函数
double getlength() { return length; }
private:
point p1, p2;//line类中有3个数据成员:point类的两个对象和length
double length;
};
//line类(组合类)的构造函数的实现
line::line(const point &xp1, const point &xp2)//:p1(xp1),p2(xp2),length(0)
{
p1 = xp1;
p2 = xp2;
double x = static_cast<double>(p1.x - p2.x);
double y = static_cast<double>(p1.y - p2.y);
length = sqrt(x*x + y*y);
}
int main() {
point mypoint1(1, 1), mypoint2(4, 5);//创建point类的两个对象
line line1(mypoint1, mypoint2);//创建line类的对象
cout << line1.getlength() << endl;
system("pause");
return 0;
}