生成类对象时,其成员可以用类的构造函数初始化。构造函数是与类同名的成员函数。程序员提供的构造函数在每次生成类对象(实例化)时自动调用。构造函数可以重载.提供初始化类对象的不同方法。数据成员应在类的构造函数中初始化或在生成对象之后设置其数值。
类的数据成员只能在类定义中初始化。
试图声明构造函数的返回类型和返回植是个语法错误。
适当时候(通常都是)应提供一十构速函数,保证每个对象正确地初始化为有意义的值。特别是指针数据类型应初始化为合法指针值或0。
每个修改对象的private数据成员的成员函数(和友元)应确保数据保持一致状态。
声明类对象时,可以在括号中提供初始化值,放在对象名后面和分号前面。这些初始化值作为
参数传递给类的构造函数。稍后会举几个构造函数调用(constructor call)的例子(注意:尽管程序
员不显式调用构造函数,但程序员仍然可以提供数据,作为参数传递给构造函数)。
图6.1time1.cpp中的构造函数将hour、minute和second初始化为0(即军用时间午夜11时)。
构造函数可以包含默认参数。图6.8重新定义Time的构造函数,该函数中每个变量的默认参数为0。通过提供构造函数默认参数,即使在构造函数调用中不提供数值,对象也能利用默认参数初始化为一致状态。程序员提供所有参数默认值(或显式不要求参数)的构造函数也称为默认构造函数(default constnlctor),即可以不用参数而调用的构造函数。一个类只能有一个默认构造函数。
// Fig. 6.8: time2.h // Declaration of the Time class. // Member functions are defined in time2.cpp // preprocessor directives that // prevent multiple inclusions of header file #ifndef TIME2_H #define TIME2_H // Time abstract data type definition class Time { public: Time( int = 0, int = 0, int = 0 ); // default constructor void setTime( int, int, int ); // set hour, minute, second void printMilitary(); // print military time format void printStandard(); // print standard time format private: int hour; // 0 - 23 int minute; // 0 59 int second; // 0 - 59 }; #endif // Fig. 6.8: time2.cpp // Member function definitions for Time class. #include <iostream.h> #include "time2.h" // Time constructor initializes each data member to zero. // Ensures all Time objects start in a consistent state. Time::Time(int hr,int min,int sec) { setTime( hr, min, sec ); } // Set a new Time value using military time. Perform validity // checks on the data values. Set invalid values to zero. void Time::setTime(int h,int m,int s) { hour = ( h >= 0 && h < 24 ) ? h : 0; minute = ( m >0 && m < 60 )? m : 0; second = ( s >= 0 && s < 60 ) ? s : 0; } // Print Time in military format void Time::printMilitary() cout << ( hour < 10 ? "O" : "" ) << hour << ":" << ( minute < 10 ? "0" : "" ) << minute; } // Print Time in standard format void Time::printStandard() cout << ( ( hour == 0 || hour == 12 ) ? 12 : hour % 12 ) << ":" <<( minute < 10 ? "0" : "" ) << minute << ":" << ( second < 10 ? "0" : "" ) << second << ( hour < 12 ? "AM" : "PM" ); } // Fig. 6.8: fig06_08.cpp // Demonstrating a default constructor // function for class Time. #include< iostream.h> #include "time2.h" int main() { Time t1, // all arguments defaulted t2(2), // minute and second defaulted t3(21, 34), // second defaulted t4(12, 25, 42), // all values specified t5(27, 74, 99); // all bad values specified cout << "Constructed with:\n" << "all arguments defaulted:\n "; t1.printMilitary(); cout << "\n "; t1.printStandard(); cout << "\nhour specified; minute and second defaulted:" << "\n "; t2.printMilitary{); cout << "\n "; t2.printStandard(); cout << "\nhour and minute specified; second defaulted:" << "\n "; t3.printMilitary(); cout << "\n "; t3.printStandard(); cout << "\nhour, minute, and second specified:" << "\n "; t4.printMilitaryO; cout << "\n "; t4.printStandard(); cout << "\nall invalid values specified:" << "\n "; t5.printMilitary(); cout << "\n "; t5.printStandardO; cout << endl; return 0; }
输出结果:
Constructed with:
all arguments defaulted
00:00
12:00:00 AM
hour specified; minute and second defaulted:
02:00
2:O0:0O AM
hour and minute specified; second defaulted:
21:34
9:34:00 PM
hour, minute, and second specified:
12:25
12:25:42 PM
all invalid values specified:
00:00
12:00:00 AM
图 6.8 构造函数使用默认参数
在这个程序中,构造函数调用成员函数setTime,将数值传人构造函数(或用默认值)保证hour 值取0到13、minute和second值取0到59。如果数值超界,则setTime将其设置为0(使数据成员保证一致状态)。
注意,Time构造函数也可以写成包含与setTime成员函数相同的语句。这样可能会使程序更有效,因为不必另外再调用setTime函数。但让Time构造函数和setTime成员函数使用相同代码会使程序维护更加困难。如果setTime成员函数的实现方法改变,则Time构造函数的实现方法也要相应 改变。Time构造函数直接调用setTime时,setTime成员函数的实现方法只要改变一次即可,这样就 可以在改变实现方法时减少错误。另外,显式声明内联的构造函数或在类定义中定义构造函数也可以提高Time构造函数的性能(后者隐含内联函数定义)。
如果类的成员函数已经提供类的构造函数(或其他成员函数)所需功能的所有部分,则从构造函数(或其他成员函数)调用这个成员函数。这样可以简化代码维护和减少修改代码实现方法时的出错机会。因此就形成了一个一般原则:避免重复代码。
只在头文件内的类定义的函数原型中声明默认函数参数值。
在头文件和成员函数定义中指定同一成员函数的默认初始化值。
图6.8的程序初始化五个Time对象:一个将三个参数指定为默认值,一个指定一个参数,一个指定两个参数.一个指定三个参数,一个指定三个无效参数。每个对象数据成员均显示实例化和初始化之后的内容。
如果类不定义构造函数,则编译器生成默认构造函数。这种构造函数不进行任何初始化,因此生成对象时,不能保证处于一致状态。
类不一定有默认构造函数。