?? 06章 類與數據抽象(一).txt
字號:
6.10 初始化類對象:構造函數
生成類對象時,其成員可以用類的構造函數初始化。構造函數是與類同名的成員函數。程序員提供的構造函數在每次生成類對象(實例化)時自動調用。構造函數可以重載.提供初始化類對象的不同方法。數據成員應在類的構造函數中初始化或在生成對象之后設置其數值。
常見編程錯誤6. 7
類的數據成員只能在類定義中初始化。
常見編程錯誤6.8
試圖聲明構造函數的返回類型和返回植是個語法錯誤。
編程技巧6.5
適當時候(通常都是)應提供一十構速函數,保證每個對象正確地初始化為有意義的值。特別是指針數
據類型應初始化為合法指針值或0。
測試與調試提示6.4
每個修改對象的private數據成員的成員函數(和友元)應確保數據保持一致狀態。
聲明類對象時,可以在括號中提供初始化值,放在對象名后面和分號前面。這些初始化值作為
參數傳遞給類的構造函數。稍后會舉幾個構造函數調用(constructor call)的例子(注意:盡管程序
員不顯式調用構造函數,但程序員仍然可以提供數據,作為參數傳遞給構造函數)。
6.11 在構造函數中使用默認參數
圖6.1time1.cpp中的構造函數將hour、minute和second初始化為0(即軍用時間午夜11時)。
構造函數可以包含默認參數。圖6.8重新定義Time的構造函數,該函數中每個變量的默認參數為0。通過提供構造函數默認參數,即使在構造函數調用中不提供數值,對象也能利用默認參數初始化為一致狀態。程序員提供所有參數默認值(或顯式不要求參數)的構造函數也稱為默認構造函數(default constnlctor),即可以不用參數而調用的構造函數。一個類只能有一個默認構造函數。
1 // Fig. 6.8: time2.h
2 // Declaration of the Time class.
3 // Member functions are defined in time2.cpp
4
5 // preprocessor directives that
6 // prevent multiple inclusions of header file
7 #ifndef TIME2_H
8 #define TIME2_H
9
10 // Time abstract data type definition
11 class Time {
12 public:
13 Time( int = 0, int = 0, int = 0 ); // default constructor
14 void setTime( int, int, int ); // set hour, minute, second
15 void printMilitary(); // print military time format
16 void printStandard(); // print standard time format
17 private:
18 int hour; // 0 - 23
19 int minute; // 0 59
20 int second; // 0 - 59
21 };
22
23 #endif
24 // Fig. 6.8: time2.cpp
25 // Member function definitions for Time class.
26 #include <iostream.h>
27 #include "time2.h"
28
29 // Time constructor initializes each data member to zero.
30 // Ensures all Time objects start in a consistent state.
31 Time::Time(int hr,int min,int sec)
32 { setTime( hr, min, sec ); }
33
34 // Set a new Time value using military time. Perform validity
35 // checks on the data values. Set invalid values to zero.
36 void Time::setTime(int h,int m,int s)
37 {
38 hour = ( h >= 0 && h < 24 ) ? h : 0;
39 minute = ( m >0 && m < 60 )? m : 0;
40 second = ( s >= 0 && s < 60 ) ? s : 0;
41 }
42
43 // Print Time in military format
44 void Time::printMilitary()
45
46 cout << ( hour < 10 ? "O" : "" ) << hour << ":"
47 << ( minute < 10 ? "0" : "" ) << minute;
48 }
49
50 // Print Time in standard format
51 void Time::printStandard()
53 cout << ( ( hour == 0 || hour == 12 ) ? 12 : hour % 12 )
54 << ":" <<( minute < 10 ? "0" : "" ) << minute
55 << ":" << ( second < 10 ? "0" : "" ) << second
56 << ( hour < 12 ? "AM" : "PM" );
57 }
58 // Fig. 6.8: fig06_08.cpp
59 // Demonstrating a default constructor
60 // function for class Time.
61 #include<iostream.h>
62 #include "time2.h"
63
64 int main()
65 {
66 Time t1, // all arguments defaulted
67 t2(2), // minute and second defaulted
68 t3(21, 34), // second defaulted
69 t4(12, 25, 42), // all values specified
70 t5(27, 74, 99); // all bad values specified
71
72 cout << "Constructed with:\n"
73 << "all arguments defaulted:\n ";
74 t1.printMilitary();
75 cout << "\n ";
76 t1.printStandard();
77
78 cout << "\nhour specified; minute and second defaulted:"
79 << "\n ";
80 t2.printMilitary{);
81 cout << "\n ";
82 t2.printStandard();
83
84 cout << "\nhour and minute specified; second defaulted:"
85 << "\n ";
86 t3.printMilitary();
87 cout << "\n ";
88 t3.printStandard();
89
90 cout << "\nhour, minute, and second specified:"
91 << "\n ";
92 t4.printMilitaryO;
93 cout << "\n ";
94 t4.printStandard();
95
96 cout << "\nall invalid values specified:"
97 << "\n ";
98 t5.printMilitary();
99 cout << "\n ";
100 t5.printStandardO;
101 cout << endl;
102
103 return 0;
104 }
輸出結果:
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.19
如果類的成員函數已經提供類的構造函數(或其他成員函數)所需功能的所有部分,則從構造函數(或其他成員函數)調用這個成員函數。這樣可以簡化代碼維護和減少修改代碼實現方法時的出錯機會。因此就形成了一個一般原則:避免重復代碼。
編程技巧6.6
只在頭文件內的類定義的函數原型中聲明默認函數參數值。
常見編程錯誤6.9
在頭文件和成員函數定義中指定同一成員函數的默認初始化值。
圖6.8的程序初始化五個Time對象:一個將三個參數指定為默認值,一個指定一個參數,一個指定兩個參數.一個指定三個參數,一個指定三個無效參數。每個對象數據成員均顯示實例化和初始化之后的內容。
如果類不定義構造函數,則編譯器生成默認構造函數。這種構造函數不進行任何初始化,因此生成對象時,不能保證處于一致狀態。
軟件工程視點6.20
類不一定有默認構造函數。
6.12 使用析構函數
析構函數是類的特殊成員函數。類的析構函數名是類名前面加上代字符(~)這種命名規則很直觀,因為本章稍后將會介紹,代字運算符是按位取反符,從這個意義上,析構函數是構造函數的反函數。
類的析構函數在刪除對象時調用,即程序執行離開初始化類對象的范圍時。析構函數本身并不實際刪除對象,而是進行系統放棄對象內存之前的清理工作,使內存可以復用于保存新對象。
析構函數不接受參數也不返回數值。類只可能有一個析構函數,不能進行析構函數重載。常見編程錯誤6.10
向析構函數傳遞參數、指定析構函數的返回值類型(即使指定void)、從析構函數返回數值或重載析構函數都是語法錯誤。
注意,前面介紹的類都沒有提供析構函數。下面要介紹幾個使用析構函數的例子。第8章將介紹析構函數適用于動態分配內存的對象類(例如數組和字符串)。第7章將介紹如何動態分配內存和釋放內存。
軟件工程視點6.21
稍后會介招,構造函數和析構函數在C++和面向對象編程中相當重要,不是這里的介紹所能說清楚的。
6.13 何時調用構造函數與析構函數
構造函數與析構函數是自動調用的。這些函數的調用順序取決于執行過程進入和離開實例化對象范圍的順序。一般來說,析構函數的調用順序與構造函數相反。但圖6.9將介紹對象存儲類可以改變析構函數的調用順序。
全局范圍中定義的對象的構造函數在文件中的任何其他函數(包括main)執行之前調用(但不同文件之間全局對象構造函數的執行順序是不確定的)。當main終止或調用exit函數時(見第18章)調用相應的析構函數。
當程序執行到對象定義時,調用自動局部對象的構造函數。該對象的析構函數在對象離開范圍時調用(即離開定義對象的塊時)。自動對象的構造函數與析構函數在每次對象進人和離開范圍時調用。
static局部對象的構造函數只在程序執行首次到達對象定義時調用一次,對應的析構函數在main終止或調用exit函數時調用。
圖6.9的程序演示了CreateAndDestroy類型的對象在幾種范圍中調用構造函數與析構函數的順序。程序在全局范圍中定義first,其構造函數在程序開始執行時調用,其析構函數在程序終止時刪除所有其他對象之后調用。
1 // Fig. 6,9: create,h
2 // Definition of class CreateAndDestroy.
3 // Member functions defined in create.cpp,
4 #ifndef CREATE_H
5 #define CREATE_H
6
7 class CreateAndDestroy {
8 public:
9 CreateAndDestroy( int ); // constructor
10 ~CreateAndDestroy(); // destructor
11 private:
12 int data;
13 };
14
15 #endif
16 // Fig, 6.9: create.cpp
17 // Member function definitions for class CreateAndDestroy
18 #include <iostream.h>
19 #include "create.h"
20
21 CreateAndDestroy::CreateAndDestroy( int value )
22 {
23 data = value;
24 cout << "Object "<< data <<" constructor";
29 }
26
27 CreateAndDestroy::~CreateAndDestroyO
28 { cout << "Object "<< data <<" destructor "<< endl; }
29 // Fig, 6.9: fig0609.cpp
30 // Demonstrating the order in which constructors and
31 // destructors are called.
32 #include <iostream.h>
39 #include "create.h"
34
35 void create( void ); // prototype
36
37 CreateAndDestroy first( 1 ); // global object
38
39 int main()
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -