关于构造函数的其他例子
讨论2: 再谈构造函数
例1. 用new创建对象数组,调用什么样的构造函数?
class Point
{
public:
Point(double xx=0, double yy=0):x(xx),y(yy)
{
cout << "调用Point构造函数" << endl;
}
private:
double x;
double y;
};
int main()
{
Point *p1= new Point[4];
return 0;
}
输出结果:
调用Point构造函数
调用Point构造函数
调用Point构造函数
调用Point构造函数
结论:用new创建对象数组,如上所示,Point类需要提供默认构造函数(构造函数没有参数,或者构造函数带默认参数,或者不提供构造函数用系统默认的构造函数)
例2. 构造函数可以是私有的吗?
class Point
{
public:
Point(double xx, double yy):x(xx),y(yy)
{
cout << "调用Point构造函数" << endl;
}
private:
Point(){} //构造函数私有
double x;
double y;
};
int main()
{
Point p1; //error:Calling a private constructor of class 'Point'
Point p2(3,4);
return 0;
}
结论:可以定义私有构造函数,例如希望定义对象时用户指定初始值。
例3. 对象可以自己调用构造函数吗?
class Point
{
public:
Point(double xx=0, double yy=0):x(xx),y(yy)
{
cout << "调用Point构造函数" << endl;
}
private:
double x;
double y;
};
int main()
{
Point p1;
p1.Point(5,5); //error:Cannot refer to type member 'Point' in 'Point' with '.'
return 0;
}
结论:对象不能自己调用构造函数
例4. 关于函数参数是传值还是传引用的问题
下面的例子Distance求两点间距离,主函数定义两个点,然后用这两个点初始化一个Distance对象,执行Distance构造函数,求出两点间距离。
class Point
{
public:
Point(double xx=0, double yy=0):x(xx),y(yy)
{
cout << "调用Point构造函数" << endl;
}
Point(const Point & p)
{
cout << "调用Point拷贝构造函数" << endl;
x = p.x;
y = p.y;
}
double GetX( ) const
{
return x;
}
double GetY( ) const
{
return y;
}
private:
double x;
double y;
};
class Distance
{
public:
//注意这里参数传递是引用
Distance(const Point& a, const Point& b):p1(a), p2(b)
{
cout << "调用Distance构造函数" << endl;
double x = p1.GetX( ) + p2.GetX( );
double y = p1.GetY( ) + p2.GetY( );
dist = sqrt(x*x + y*y);
}
double GetDist( )
{
return dist;
}
private:
Point p1, p2;
double dist;
};
int main( )
{
Point p1(1.1, 2.2), p2(3.3, 4.4);
Distance d(p1, p2);
cout << "the distance is " << endl;
cout << d.GetDist( ) << endl;
return 0;
}
输出结果:
调用Point构造函数
调用Point构造函数
调用Point拷贝构造函数
调用Point拷贝构造函数
调用Distance构造函数
the distance is
7.93221
结果分析:主函数第一个语句输出前两行内容“调用Point构造函数”,主函数第二个语句Distance d(p1, p2);输出接下来的三行内容,当执行Distance构造函数参数初始化p1(a), p2(b)时共调用Point拷贝构造函数两次。
进一步解释参数传递是引用传递,主函数执行这条语句Distance d(p1, p2);调用构造函数,参数传递,即const Point &a=p1, &b=p2; 这就是给已有对象(主函数的p1和p2)起了别名a和b,没有新的点对象产生。因为没有产生新对象,所以系统不会调用(拷贝)构造函数。即参数传递是引用时不调用拷贝构造函数!
如果将Distance构造函数修改如下,上面的代码其它地方不变,输出结果为:
//注意这里,参数传递是值传递
Distance(const Point a, const Point b):p1(a), p2(b)
{
cout << "调用Distance构造函数" << endl;
double x = p1.GetX( ) + p2.GetX( );
double y = p1.GetY( ) + p2.GetY( );
dist = sqrt(x*x + y*y);
}
输出结果:
调用Point构造函数
调用Point构造函数
调用Point拷贝构造函数
调用Point拷贝构造函数
调用Point拷贝构造函数
调用Point拷贝构造函数
调用Distance构造函数
the distance is
7.93221
解释参数传递是值传递的情况,主函数执行这条语句Distance d(p1, p2);调用构造函数,参数传递,即const Point a=p1, b=p2; 这就是用已有对象初始化新对象,系统自动调用拷贝构造函数。
对比输出结果:多了两行输出,多执行了两次调用Point拷贝构造函数
结论:参数传递如果是值传递,会调用拷贝构造函数,产生新对象;参数传递如果是引用传递,只是给实参起了别名,没有定义新对象,没有调用拷贝构造函数。引用方式传参显然更好,推荐大家参数传递这样写const Point& a,也就是当传值和传引用都可以时首选传引用,为了避免对实参的修改,请加上const。
例5. 关于函数类型是类对象还是对象引用的问题
含义与函数参数是传参还是传引用的问题类似,函数类型是类类型,表示函数执行结束返回调用处时系统自动调用拷贝构造函数(你如果没写,系统会有默认的拷贝构造函数),产生新的无名临时对象,如果函数类型是类引用,表示没有新对象产生。