今天在论坛上看到一个求助问题,觉得很有意义,就专门研究了一下,又学到了新的东西!这是一个关于默认构造函数在什么时候会被调用的问题,这也是我一直以来学习C++的一个盲区!特此发文,以飨读者!
有这样一个程序:
#include "stdafx.h" #include <iostream> #include <string> #include <cmath> using namespace std; class Point{ private: int x,y; public: Point(int xx,int yy){ x=xx; y=yy; } Point(Point &p); }; Point::Point(Point &p){ x=p.x; y=p.y; cout<<"Point的复制构造函数:(" << x << " "<< y << " )"<<endl; } class Line{ private: Point p1,p2; double length; public: Line(Point xp1):p1(xp1){}; double getLen(){ return length; } }; int main() { Point pa(1, 1) , pb(2, 2); Line line(pa); return 0; }在class line的参数初始化列表中会有一个语法检查错误:error C2512: “Point”: 没有合适的默认构造函数可用!
很奇怪的错误,虽然没有定义Point的默认构造函数,但是这里也没有地方去调用这个默认构造函数啊!难道是Point xp1调用的吗?当然不是啊,这只是一个变量声明,不是定义,并不需要调用default构造函数,p1(xp1)调用的是copy构造函数,也没有调用default构造函数!
随后我在Point类中加上了默认构造函数的定义,错误消失了,而且这个默认的构造函数只被调用了一次,可是没法跟踪到到底是谁调用的这个默认构造函数,一度想通过在默认构造函数中打印出调用对象的方式来侦查调用者,但是百度了很多地方都没有找到方法,只能通过其他的方式来查看了!
然后又想到,在这个参数初始化表里面,对Line的成员对象p1进行了初始化,但是并没有对p2初始化,难道是p2这个成员有问题?我把程序改到默认的对所有成员在参数初始化列表中进行初始化的方式上来,即:
#include "stdafx.h" #include <iostream> #include <string> #include <cmath> using namespace std; class Point{ private: int x,y; public: Point(int xx,int yy){ x=xx; y=yy; } Point(Point &p); }; Point::Point(Point &p){ x=p.x; y=p.y; cout<<"Point的复制构造函数:(" << x << " "<< y << " )"<<endl; } class Line{ private: Point p1,p2; double length; public: Line(Point xp1, Point xp2):p1(xp1), p2(xp2){}; double getLen(){ return length; } }; int main() { Point pa(1, 1) , pb(2, 2); Line line(pa, pb); return 0; }同样没有定义Point的默认构造函数,但是这次编译运行都通过了!仅仅是在参数初始化列表中加了对p2的初始化而已,看来是p2有问题了!
随后我在Point类中加上默认构造函数的实现,运行之后发现,此次默认构造函数根本没有任何人调用!!!
看来问题很明朗了,前面那个例子里面默认构造函数是被p2调用的,问题是:为什么没有在参数初始化列表中出现的对象成员会调用其默认构造函数呢?赶快查阅葵花宝典——《c++ primer》,找到构造函数那部分,终于找到了答案!《c++ primer》p388明确的写到了:
在构造函数初始化列表中没有显示提及的每个成员,运行该类型的默认构造函数,来初始化类类型的数据成员!
所以,一个良好的习惯就是:一定要在构造函数初始化列表中尽量初始化每一个成员!