C++ 入門指南 V2.00 - 單元 14 - Encrypt 類別




類別 (class) 為 C++ 開發軟體 (software) 的要角,因為類別用來設計物件,軟體的實際運作則是藉由物件與物件的互動。我們接下來進入實際開發軟體的階段,最後會發展出一個 GUI 軟體



我們打算發展的一個替英文句子編密碼的軟體,主要功能是做小寫字母的替換,例如 "There is no spoon." 可能變成以下任一個


Tfqdq ki jo itooj.

Tcnan hf gl fqllg.

Tczmz dn ij nkjji.

Tgfsf pb ir barri.

Tdcpc my fo yxoof.


首先,我們要發展 Encrypt 類別,主要功能是建立一個英文小寫字母的對換表格,藉由這個表格,我們可以將英文句子中的小寫英文字母進行對換,最終開發圖形使用者介面 (graphical user interface) 的 EncryptWindow 類別。


GUI 的外觀如下圖



我們的 GUI 設計會採用第三方程式庫 (third party library) Qt ,然後利用 Qt Creator 的 IDE 寫程式,並利用 Qt Creator 附的 Designer 設計 GUI , Qt 為跨平台的程式庫,同樣 Qt Creator 也是跨平台的整合開發環境,因此在各平台的使用都大致相同。

有兩個可供輸入的文字欄位 (text field) ,其中一個我們作為輸出的顯示訊息之用,另有三個標籤 (label) ,顯示文字的提示訊息,七個按鈕 (button) ,提供「新建」、「開啟」、「儲存」 Encrypt 物件,與「編碼」、「解碼」所輸入的英文句子,「清除」所有輸入欄位,以及「拷貝」輸出結果等的功能。


現在我們先來看看所有功能的核心,也就是 Encrypt 類別,我們的目的是,建立一個小寫英文字母的轉換表格,然後編碼、解碼都可直接依據這個表格。我們打算用下面的數學公式建立表格


y = a * x + b

m = y % n

r = m + diff


這裡的概念是利用字元的 ASCII 編碼順序,假設 x 為字元的原始編碼, ASCII 編碼中 'a'97 ,然後將 x 乘上變數 (variable) a , 再加上變數 b ,假設兩者均是 09 的隨機整數,這樣便得到 y 的值。


然後將 y 除以 n 取得餘數 mn 為所要轉換的字元數量,英文小寫字母共有 26 個,所以這裡 n 等於 26 ,因此 m 等於 025 之間的整數值。最後將 m 加上 diffdiff 也就是編碼系統的差值,由於 ASCII 中 'a'97 ,所以這裡 diff 要以 97 代入。


因此,餘數 0 的字元會替換成 'a' ,餘數 1 的字元會被替換成 'b' ,餘數 2 的字元會被替換成 'c' ,餘下 23 個字元類推。這樣的計算需要進行 n 次,也就是 26 次,我們最後得到一組餘數與相對應字元的表格,這就是我們需要的表格了。


重複 n 次,我們需要一個迴圈 (loop) ,由於重複次數確定,因此 for 迴圈 (for loop) 很適合,那我們要用什麼東西來儲存這個表格呢?嗯,標準程式庫 (standard library) 中有許多的資料結構 (data structure) ,可以依資料特性有效率的處理資料,這裡,我們利用字串 (string) 就可以了。


字串為字元陣列 (character array) 的物件 (object) ,因此字串裡是由字元 (character) 當成元素 (element) ,也保有陣列 (array) 的特性,例如利用從 0 開始的索引值存取每個字元,這也完全符合我們計算餘數從 0 開始的需求。


因此,我們要替 Encrypt 宣告一個字串型態的的資料成員 (data member) , code_array 為二十六個英文小寫字母的密碼對照表格


    private:
       // 密碼表字串
       string code_array;

因此就需要存取函數 (accessor) 與修改函數 (mutator) ,也就是 get_code_array()set_code_array() ,另外加上建構函數 (constructor) 跟編碼、解碼用的 ToEncode()ToDecode() 兩個成員函數 (member function) ,我們先寫一個發展中的 encrypt01.h ,如下


001 // 從標準程式庫中引入 string
002 #include <string>
003
004 // 使用 std 中的 string 名稱
005 using std::string;
006
007 // 宣告 Encrypt 類別
008 class Encrypt {
009    public:
010       // 宣告建構函數
011       Encrypt();
012       // 宣告 setter 與 getter 成員函數
013       void set_code_array();
014       string get_code_array();
015       // 宣告編碼、解碼的成員函數
016       string ToEncode(string);
017       string ToDecode(string);
018
019    private:
020       // 密碼表字串
021       string code_array;
022 };
023
024 /* 檔名: encrypt01.h
025    作者: Kaiching Chang
026    時間: 2014-5 */

注意這裡,原本我們的範例使用 using 的地方都是連帶 namespace


    using namespace std;

這裡改成指定的名稱


004 // 使用 std 中的 string 名稱
005 using std::string;

兩者實際的差別不大,因為編譯器編譯時會將程式作最佳化,因此編譯完成的執行檔只會放進必要的東西,而我們改成指定名稱的寫法,主要的原因是讓我們自己清楚用到標準程式庫中的哪些東西,所以看範例開頭 using 的部份就一目瞭然了。


我們看看宣告在 public 的成員函數


009 public:
010    // 宣告建構函數
011    Encrypt();
012    // 宣告 setter 與 getter 成員函數
013    void set_code_array();
014    string get_code_array();
015    // 宣告編碼、解碼的成員函數
016    string ToEncode(string);
017    string ToDecode(string);

標頭檔 (header file) 宣告 (declare) 成員函數時,參數列 (parameter list) 只需要宣告型態 (type) 即可,實作檔再補上實際的參數 (parameter) 名稱即可。

這裡我們看到的是未來發展 Encrypt 的規格,編碼由 ToEncode() 負責,解碼則是 ToDDecode() ,我們在這裡先宣告函數原型,後續單元再陸續實作。


下面我們先來實作 set_code_array() ,把數學公式寫成程式碼,實際建立 code_array 囉!


中英文術語對照


類別 class
軟體 software
圖形使用者介面 graphical user interface
第三方程式庫 third party library
文字欄位 text field
標籤 label
按鈕 button
變數 variable
迴圈 loop
for 迴圈 for loop
標準程式庫 standard library
資料結構 data structure
字串 string
字元陣列 character array
物件 object
字元 character
元素 element
陣列 array
資料成員 data member
存取函數 accessor
修改函數 mutator
成員函數 member function
建構函數 constructor
標頭檔 header file
宣告 declare
參數列 parameter list
型態 type
參數 parameter

重點整理


  1. Encrypt 類別的主類功能是轉換句子中的英文小寫字母,最後作為 GUI 軟體的核心部分。
  2. Encrypt 類別以數學公式建立英文字母的轉換表格,用字串當成員變數儲存表格。
  3. ASCII 中, 'a' 的整數值為 97
  4. 標準程式庫中有許多有用的資料結構,字串即是一例,字串是由字元所組成的物件,保有字元陣列的特性。
  5. 程式的發展通常是逐步來的,標頭檔則作為程式的規格。

問題與討論


  1. 為什麼 Encrypt 類別是要當作 GUI 軟體的核心?不能讓 Encrypt 類別直接成為大展神威的 GUI 軟體嗎?
  2. 除了數學公式外,有其他的方式可以建立轉換表格嗎?
  3. 為什麼程式的發展要逐步來?不能一次到位嗎?
  4. 陣列是什麼樣的資料結構?對於儲存資料有什麼方便性?

練習


  1. 陣列的宣告是型態後加上識別字與中括弧,例如宣告大小為 10 的整數陣列像是 int a[10]; ,這時 a 就是屬於整數陣列的變數,存取與設定陣列元素則用中括弧加索引值,例如 a[0] 取得或設定第一個元素, a[6] 取得或設定第 7 個元素。寫一個程式 exercise1401.cpp ,設定一個具有 10 元素的整數陣列,隨意設定 10 個元素的初值。
  2. 寫一個程式 exercise1402.cpp ,裡頭用迴圈建立一個儲存英文字母表的字元陣列。
  3. 猜數字遊戲是一種猜測四位不重複數字的小遊戲,依猜測答案給 AB 的數量, A 為對的數字及位置, B 為對的數字錯的位置,寫一個程式 exercise1403.cpp ,自訂答案 answer 值,然後印出 answer

the end

沒有留言: