類是 C++ 中最重要的特征。C++ 語言的早期版本被命名為“帶類的 C(Cwith Classes)”,以強調類機制的中心作用。隨著語言的演變,創建類的配套支持也在不斷增加。語言設計的主要目標也變成提供這樣一些特性:允許程序定義自己的類型,它們用起來與內置類型一樣容易和直觀。
類的定義和聲明
隱含的this指針
構造函數
static類成員
一個實例
為了增進讀者對上述文字的理解,這裡給出一個實例,源自《C++ Primer》習題12.13:擴展Screen類以包含move、set和display操作通過執行如下表達式來測試類:
// 將光標移至指定位置,設置字符並顯示屏幕內容
myScreen.move(4,0).set('#').display(cout);
答案如下:
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class Screen { 7 public: 8 typedef string::size_type index; 9 char get() const { return contents[cursor]; } 10 inline char get(index ht, index wd) const; 11 index get_cursor() const; 12 Screen(index hght, index wdth, const string &cntnts); 13 14 // 增加三個成員函數 15 Screen& move(index r, index c); 16 Screen& set(char); 17 Screen& display(ostream &os); 18 19 private: 20 std::string contents; 21 index cursor; 22 index height, width; 23 }; 24 25 Screen::Screen(index hght, index wdth, const string &cntnts) : 26 contents(cntnts), cursor(0), height(hght), width(wdth) { } 27 28 char Screen::get(index r, index c) const 29 { 30 index row = r * width; 31 return contents[row + c]; 32 } 33 34 inline Screen::index Screen::get_cursor() const 35 { 36 return cursor; 37 } 38 39 // 增加的三個成員函數的定義 40 Screen& Screen::set(char c) 41 { 42 contents[cursor] = c; 43 return *this; 44 } 45 46 Screen& Screen::move(index r, index c) 47 { 48 index row = r * width; 49 cursor = row + c; 50 return *this; 51 } 52 53 Screen& Screen::display(ostream &os) 54 { 55 os << contents; 56 return *this; 57 } 58 59 int main() 60 { 61 // 根據屏幕的高度、寬度和內容的值來創建 62 Screen Screen myScreen(5, 6, "aaaaa\naaaaa\naaaaa\naaaaa\naaaaa\n"); 63 64 // 將光標移至指定位置,設置字符並顯示屏幕內容 65 myScreen.move(4, 0).set('#').display(cout); 66 67 return 0; 68 } View Code
這個解決方法已滿足了題目提出的要求,但存在一些缺陷:
(1) 創建Screen對象時必須給出表示整個屏幕內容的字符串,即使有些位置上沒有內容。
(2) 顯示的屏幕內容沒有恰當地分行,而是連續顯示,因此(4,0)位置上的'#',在實際顯示時 不一定正好在屏幕的(4,0)位置,顯示效果較差。
(3) 如果創建的Screen對象是一個const對象,則不能使用display函數進行顯示(因為const對 象只能使用const成員)。
(4) 如果move操作的目的位置超出了屏幕的邊界,會出現運行時錯誤。
要解決第一個缺陷,可以如下修改構造函數:
1 Screen::Screen(index hght, index wdth, const string &cntnts = " "): cursor(0), height(hght), width(wdth) 2 { 3 // 將整個屏幕內容置為空格 4 contents.assign(hght*wdth, ' '); 5 // 用形參string對象的內容設置屏幕的相應字符 6 if (cntnts.size() != 0) 7 contents.replace(0, cntnts.size(), cntnts); 8 }
要解決第二個缺陷,可以如下修改display函數:
1 Screen& Screen::display(ostream &os) 2 { 3 string::size_type index = 0; 4 while (index != contents.size()) 5 { 6 os << contents[index]; 7 if ((index+1) % width == 0) 8 { 9 os << '\n'; 10 } 11 ++index; 12 } 13 return *this; 14 }
要解決第三個缺陷,可以在Screen類定義體中增加如下函數聲明: const Screen& display(ostream &os) const; 聲明display函數的一個重載版本,供 const對象使用。
要解決第四個缺陷,可以如下修改move函數:
1 Screen& Screen::move(index r, index c) 2 { 3 // 行、列號均從0開始 4 if (r >= height c >= width) 5 { 6 cerr << "invalid row or column" << endl; 7 throw EXIT_FAILURE; 8 } 9 10 index row = r * width; 11 cursor = row + c; 12 return *this; 13 }
經過如上述幾處修改,整個程序的健壯性,魯棒性都得到了改善。全部代碼如下:
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class Screen { 7 public: 8 typedef string::size_type index; 9 char get() const { return contents[cursor]; } 10 inline char get(index ht, index wd) const; 11 index get_cursor() const; 12 13 Screen(index hght, index wdth, const string &cntnts); 14 15 Screen& move(index r, index c); 16 Screen& set(char); 17 Screen& display(ostream &os); 18 const Screen& display(ostream &os) const; 19 20 private: 21 std::string contents; 22 index cursor; 23 index height, width; 24 }; 25 26 Screen::Screen(index hght, index wdth, const string &cntnts = "1"): 27 cursor(0), height(hght), width(wdth) 28 { 29 contents.assign(hght*wdth, '1'); 30 31 if (cntnts.size() != 0) 32 contents.replace(0, cntnts.size(), cntnts); 33 } 34 35 36 char Screen::get(index r, index c) const 37 { 38 index row = r * width; 39 return contents[row + c]; 40 } 41 42 inline Screen::index Screen::get_cursor() const 43 { 44 return cursor; 45 } 46 47 Screen& Screen::set(char c) 48 { 49 contents[cursor] = c; 50 return *this; 51 } 52 53 Screen& Screen::move(index r, index c) 54 { 55 if (r >= height || c >= width) 56 { 57 cerr << "invalid row or column" << endl; 58 throw EXIT_FAILURE; 59 } 60 61 index row = r * width; 62 cursor = row + c; 63 64 return *this; 65 } 66 67 Screen& Screen::display(ostream &os) 68 { 69 string::size_type index = 0; 70 71 while (index != contents.size()) 72 { 73 os << contents[index]; 74 if ((index + 1) % width == 0) 75 { 76 os << '\n'; 77 } 78 ++index; 79 } 80 return *this; 81 } 82 83 const Screen& Screen::display(ostream &os) const 84 { 85 string::size_type index = 0; 86 87 while (index != contents.size()) 88 { 89 os << contents[index]; 90 if ((index + 1) % width == 0) 91 { 92 os << '\n'; 93 } 94 ++index; 95 } 96 return *this; 97 } 98 99 int main() 100 { 101 Screen myScreen(10,30); 102 //Screen myScreen(5, 6, "aaaaa\naaaaa\naaaaa\naaaaa\naaaaa\n"); 103 myScreen.move(4, 0).set('#').display(cout); 104 105 system("pause"); 106 107 return 0; 108 } View Code