?? 06章 類與數據抽象(一).txt
字號:
76 t.printStandard();
77
78 t.setTime( 99, 99, 99 ); // attempt invalid settings
79 count << "\n\nAfter attempting invalid settings:\n"
80 << "Military time:";
81 t.printMilitary();
82 cout << "\.Standard time:";
83 t.printStamdard();
84 cout << endl;
85 return 0;
86 }
輸出結果:
The initial military time is 00:00
The initial standard time is 12:00:00 AM
Military time after setTime is 13:27
Standard time after setTime is 1:27:06 PM
After attempting invalid settings:
Military time: 00:00
Standard time: 12:00:00 AM
圖 6.5 將Time類的接口與實現方法分離
注意類聲明放在下列預處理代碼中:
// prevent multiple inclusions of header file
#ifndef TIME1_H
#define TIME1_H
...
#defint
建立大程序時,其他定義和聲明也放在頭文件中。上述預處理指令使得在定義了TIME1_H名字時不再包含#ifndef和#endif之間的代碼。如果文件中原先沒有包含頭文件,則TIME1_H名字由#define指令定義,并使該文件包含頭文件語句。如果文件中已經包含頭文件,則TIME1_H名字已經定義,不再包含頭文件語句。多次包含頭文件語句通常發生在大程序中,許多頭文件本身已經包含其他頭文件。注意:預處理指令中符號化常量名使用的規則是把頭文件名中圓點(.)換成下劃線。
測試與調試提示 6. 2
用#ifdef、#define和#endif預處理指令防止一個程序中多次包合相同的頭文件。
編程技巧6.2
頭文件的#ifdef和#define頇處理指令中用頭文件名,井將圓點換成下劃線,
6.8 控制對成員的訪問
成員訪問說明符public和private(和第9章“繼承”中介紹的protected)可以控制類數據成員和成員函數的訪問。類的默認訪問模式是private,因此類的首部和第一個標號之間的所有成員的類型都是private。每個標號之后,采用該標號表示的方式,直到遇到下一個標號或遇到類定義的右花括號(})。標號public、private和protedted可以重復,但這種情況不常用,容易造成混亂。
類的private成員只能由類的成員函數(和第7章介紹的友元)訪問,public成雖則可以由程序中的任何函數訪問。
public成員的主要用途是向類的客戶提供類的服務(行為),這組服務形成類的public接口。類的客戶不必關心類如何完成任務。類的private成員和public成員函數的定義是類的客戶無法訪問的。
這些組件形成類的實現方法(implementation)。
軟件工程視點6.13
C++提倡程序獨立于實現方法。對于獨立于實現方法的代碼,改變類的實現方法時,代碼不需要改變,但可能需要重新編譯。
常見編程錯誤6.6
除了由類的成員函數(和第7章介紹的友元)訪問外,其他函數想訪問類的private成員是個語法錯誤。
圖6.6演示了private類成員只能用public成員函數通過public類接口訪問。編譯這個程序時,編譯器產生兩個錯誤,表示每個語句中指定的private成員無法訪問。圖6.6包含time1.h并和圖6.5的time1.cpp一起編譯。
編程技巧6.3
如果在類定義中先列出private成員,盡管程序默認的訪問模式為private,但最好還是顯式使用private標號,這樣可以使程序更清晰。我們喜歡先列出public成員以強調類的接口。
1 // Fig. 6.6:fig06 06.cpp
2 // Demonstrate errors resulting from attempts
3 // to access private class members.
4 #include <iostream.h>
5 #include "time1.h"
6
7 int main()
8 {
9 Time t;
10
11 // Error: 'Time::hour' is not accessible
12 t.hour = 7;
13
14 // Error: 'Time::minute' is not accessible
15 cout << "minute =" << t.minute;
16
17 return 0;
18 }
輸出結果:
Compilin9 FIG06 06.CPP:
Error FIG06 06.CPP 12: 'Time::hour' is not accessible
Error FIG06_06.CPp 15: 'Time::minute' is not accessible
圖6.6 訪問類的private成員的錯誤
編程技巧6.4
盡管public和private標號可以重復和混合,但最好先將所有public成員列成一組,然后將所有private成
員列成一組,這樣可以使客戶集中注意類的public接口,而不是注意類的實現方法。
軟件工程視點6.14
讓類的所有數據成員保持private。讓Public成員函數設置private數據成員的值并取得private數據成員的
值。這種結構能隱藏類的實現方法,減少錯誤和提高程序的可修改性。
類的客戶可能是另一類的成員函數,也可能是全局函數(即文件中類c語言的“松散”函數,不是任何類的成員函數)。
類成員的默認訪問方式為private。類成員的訪問方式可以顯式設置為public、protected(見第9章)和private。struct成員的默認訪問方式為public。struct的成員的訪問方式也可以設置為Public、protected或private。
較件工程視點6.15
類設計人員用public、protected或private成員實現信息隱藏和最低權限原則。
類數據為private并不表示客戶不能改變這個數據??蛻艨梢酝ㄟ^這個類的成員函數或友元改變這個數據,但這些函數的設計應保證數據完整性。
訪問類的private數據應當用稱為訪問函數access funotion)或訪問方法(access method)的成員函數嚴格控制。例如,要讓客戶讀取private數據的值,類可以提供一個get函數。要讓客戶修改private數據的值,類可以提供一個set函數。這種修改似乎會破壞private數據的專用性,但set成員函數可以提供數據驗證功能(如范圍檢查),保證數值設置正確,set函數也可以在接口使用的數據形式與實現方法使用的數據形式之間進行換算。get函數不必以原始形式顯示數據,該函數可以編輯數據,限制客戶可以看到的數據。
軟件工程視點6.16
類設計人員不必提供每個private數據成員的get和set函數,只在需要時才提供數據成員的get和set函數。
測試與調試提示6.3
將類的數據成員指定為private、類的成員函數指定為public有助于調試,因為數據操作問題局部化在類成員函數或類的友元中。
6.9 訪問函數與工具函數
并非所有成員函數都要用public指定為類接口的一部分。有些成員函數保持private,作為類中 其他函數的工具函數(utility function)。
軟件工程視點6.17
成員函數分為幾大類:讀取和返回私有數據成員值的函數、設置私有數據成員值的函數、實現類特性的 函數和進行各種類操作的函數(如初始化類對象、指定類對象、將類與內部類型或其他類進行相互轉換以及處理奧對象內存)。
訪問函數可以讀取和顯示數據。訪問函數的另一常見用法是測試條件的真假,這種函數稱為判定函數(predicate funchon)。任何容器類都有的isEmpty函數(如鏈表、堆棧和隊列)就是判定函 數。程序先測試isEmpty,再從容器對象中讀取下一個項目。判定函數isFull于測試容器類對象還有沒有多余的存儲空間。Time類的判定函數包括isAM和isPM。
圖6.7演示了工具函數(或稱為幫助函數)的使用。工具函數不是類接口的一部分,而是private成員函數,支持類中其他函數的操作。類的客戶不能使用工具函數。
1 // Fig. 6.7: salesp.h
2 // SalesPerson Class definition
3 // Member functions defined in salesp.cpp
4 #ifndef SALESPH
5 #define SALESPH
6
? class SalesPerson {
8 public:
9 SalesPerson(); // constructor
10 void getSalesFromUser(); // get sales figures from keyboard
11 void setSales( int, double ); // User supplies one month's
12 // sales figures.
13 void printAnnualSales();
14
15 private:
16 double totalAnnualSales(); // utility function
17 double sales[ 12 ]; // 12 monthly sales figures
18 };
19
20 #endif
21 // Fig. 6.7: salesp.cpp
22 // Member functions for class SalesPerson
23 #include <iostream.h>
24 #include <iomanip.h>
26
27 // Constructor function initializes array
28
29 {
30 for (int i = 0; i < 12; i++ )
31 sales[ i ] = 0.0;
32 }
34 // Function to get 12 sales figures from tha user
35 // at the keyboard
37 {
38 double salesFigure;
40 for (int i = 0; i < 12; i++ ) {
41 cout << "Enter sales amountfor month"
<< i + 1 << ": ";
43 cin >> salesFigure;
44 setSales( i, salesFigure );
45 }
46 }
47
48 // Function to set one of the 12 monthly sales figures.
49 Note that the month value must be from 0 to 11
50 void SalesPerson::setSales( int month, double amount )
51 {
52 if ( month >= 0 && month < 12 && amount > 0 )
53 sales[ month ] = amount;
54 else
55 cout << "Inalid month or sales figure" << endl;
56 }
57
58 // Print the total annual sales
59 void SalesPerson::printAnnualSales()
6O {
61 cout << setprecision( 2 )
62 << setiosflags( ios::fixed I ios::showpoint )
63 << "\nThe total annual sales are: $"
64 << totalAnnualSales() << endl;
65 }
67 // Private utility function to total annual sales
68 double SalesPerson::totalAnnualSales()
69 {
70 double total = 0.0;
71
72 for (int i = 0; i < 12; i++ )
73 total += sales[ i ];
74
75 return total;
76 }
77 // Fig.67:fig06_07.cpp
78 // Demonstrating a utility function
79 // Compile with salesp.cpp
80 #include "salesp.h"
81
82 int main()
83 {
84 SalesPerson s; // create SalesPerson object s
85
86 s.getSalesFromUser(); // note simple sequential code
87 s.printAnnualSales(); // no control structures in main
88 return 0;
89 }
輸出結果:
Enter sales amount for month 1:5314.76
Enter sales amount for month 2:4292.38
Enter sales amount for month 3:4589.83
Enter sales amount for month 4:5534.03
Enter sales amount for month 5:4376.34
Enter sales amount for month 6:5698.45
Enter sales amount for month 7:4439.22
Enter sales amount for month 8:5893.57
Enter sales amount for month 9:4909.67
Enter sales amount fez month 10:5123.45
Enter sales amount for month 11:2024.97
Enter sales amount for month 12:5923.92
The total annual sales are: $60120.58
圖 6.7使用工具函數
SalesPerson類中的表示12個月銷售數據的數組用構造函數初始化為0,并用setSales函數設置為用戶提供的值。public成員函數printAnnualSales打印最近11個月的總銷售額。工具函數,TotalAnnualSales為PrintAnnualSales計算12個月的總銷售額。成員函數printAnnudSales將銷售數據轉換為美元金額格式。
注意main中只有一個簡單的成員函數調用,沒有任何控制結構。
軟件工程視點6.18
面向對象編程的一個現象是定義類之后,生成和操作這個類的對象通常只要一個簡單的成員函數調用,
沒有任何或只有少量控制結構。相反,類成員函數的實現則通常需要控制結構。
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -