构造函数中参数的值既可以通过实参传递,也可以指定为某些默认值,即如果用户不指定实参值,编译系统就使形参取默认值。在实际生活中常有一些这样的初始值:计数器的初始值一般默认为0,战士的性别一般默认为"男",天气默认为"晴"等,如果实际情况不是这些值,则由用户另行指定。这样可以减少输入量。
在之前的文章中介绍过,在函数中可以使用有默认值的参数。在构造函数中也可以采用这样的方法来实现初始化。
编写程序:
运行结果:
程序分析:
由于在定义对象box1时没有给实参,系统就调用默认构造函数,各形参的值均取默认值10,即
box1.height=10;box1.width=10;box1.length=10
在定义对象box2时只给定一个实参15,它传给形参h(长方柱的高),形参w和len未得到实参过来的值,就取默认值10,即
box2.height=15;box2.width=10;box2.length=10;
同理:
box3.height=15;box3.width=30;box3.length=10;
box4.height=15;box4.width=30;box4.length=20;
程序中对构造函数的定义(第12~16行)也可以改写成参数初始化表的形式:
Box::Box(int h,int w,int len):height(h),width(w),length(len){}
只需要一行就够了,简单方便。
可以看到,在构造函数中使用默认参数是方便而有效的,它提供了建立对象时的多种选择,它的作用相当于好几个重载的构造函数。它的好处是:即使在调用构造函数时没有提供实参值,不仅不会出错,而且还确保按照默认的参数值对对象进行初始化。尤其在希望对每一个对象都有同样的初始化状况时用这种方法更为方便,不需要输入数据,对象全按事先指定的值进行初始化。
说明:
(1)应该在什么地方指定构造函数的默认参数?应在声明构造函数时指定默认值,而不能只在定义构造函数时指定默认值。因为类声明是放在头文件中的,它是类的对外接口,用户是可以看到的,而函数的定义是类的实现细节,用户往往是看不到的。在声明构造函数时指定默认参数值,使用户知道在建立对象时怎样使用默认参数。
(2)程序第5行在声明构造函数时,形参名可以省略,即写成
Box(int=10,int=10,int=10);
(3)如果构造函数的全部参数都指定了默认值,则在定义对象时可以给一个或几个实参,也可以不给出实参。由于不需要实参也可以调用构造函数,因此全部参数都指定了默认值的构造函数也属于默认构造函数。前面曾提到过:一个类只能有一个默认构造函数,也就是说,可以不用参数而调用的构造函数,一个类只能有一个。其道理是显然的,是为了避免调用时的歧义性。如果同时定义了下面两个构造函数,是错误的。
Box(); //声明一个全部参数都指定了默认值的构造函数
Box(int=10,int=10,int=10); //声明一个无参的构造函数
在建立对象时,如果写成
Box box1;
编译系统无法识别应该调用哪个构造函数,出现歧义性,编译时报错。应该避免这种情况。
(4)在一个类中定义了全部是默认参数的构造函数后,不能再定义重载构造函数。例如在一个类中有以下构造函数的声明:
Box(int=10,int=10,int=10); //指定全部为默认参数
Box(); //声明无参的构造函数
Box(int,int); //声明有两个参数的构造函数
若有以下定义语句:
Box box1; //是调用上面第1个构造函数,还是调用第2个构造函数
Box box2(15,30) //是调用上面第1个构造函数,还是调用第3个构造函数
应该执行哪一个构造函数呢?出现歧义性。但如果构造函数中的参数并非全部为默认值时,就要分析具体情况。如有以下3个原型声明:
Box(); //无参的构造函数
Box(int,int=10,int=10); //有一个参数不是默认参数
Box(int,int); //有两个参数构造函数
若有以下定义对象的语句:
Box box1; //正确,不出现歧义性,调用第1个构造函数
Box box2(15); //调用第2个构造函数
Box box3(15,30); //错误,出现歧义性
很容易出错,要十分仔细。因此,一般不应同时使用构造函数的重载和有默认参数的构造函数。