972 Spring C++ 程式作業五:
        簡易檔案匣與檔案設計 I

說明

這個作業還有下次的作業希望大家模擬設計一個簡單的資料匣管理程式, 假設操作者在一個資料匣中可以存放多個資料檔案(每一個檔案有檔案名稱和檔案內容), 可以對這些儲存下來的資料做一些基本的處理。基本的功能類似檔案系統介面的操作與管理, 可以新增檔案, 可以新增資料匣, 可以搜尋檔案名稱, 可以搜尋檔案內容, 可以刪除檔案與資料匣

範例執行程式prog5_v1.exe, 資料檔案prog5a.in, 下載後可以直接透過鍵盤交談式執行,也可以用

直接執行資料檔案 prog5a.in 中的命令, 程式結束後會將所建立的資料匣及檔案架構存檔, 下次執行會重新讀入

作業目標:

  1. 練習以 C++ 語法實作指定的類別架構 (包括繼承與組合)

  2. 練習物件間的分工合作 (封裝與委託)

  3. 練習序列化 (Serialization) 讀取檔案與寫入檔案

  4. 練習 iostream 中基本的鍵盤輸入與螢幕輸出

  5. 練習使用 string 與 vector 等等基本的樣板類別

  6. 練習覆蓋 (overriding) 基礎類別中的虛擬介面函式

  7. 練習使用多型指標

  8. 練習使用異質容器

程式要求

  1. 程式功能要求如下:

    1. 可以在階層式的資料匣中移動 (使用者在操作時有一個目前資料匣的狀態)

    2. 新增檔案: 輸入資料檔案的名稱和資料檔案的內容, 在一個資料匣中不可以有兩個相同檔案名稱的檔案/資料匣

    3. 新增資料匣: 輸入資料匣的名稱, 在一個資料匣中不可以有兩個相同名稱的子資料匣/檔案

    4. 刪除指定檔案

    5. 刪除指定資料匣以及所有下層的檔案和子資料匣

    6. 允許使用者查詢目前資料匣中有哪些檔案與子資料匣

    7. 允許使用者查詢目前資料匣及子資料匣中有哪些檔案與子資料匣

    8. 允許使用者查詢某一個指定檔案的內容

    9. 允許使用者以檔名搜尋第一個具有指定名稱的檔案或資料匣

    10. 允許使用者以檔案內容的關鍵字串搜尋第一個包括此字串的檔案

    11. 計算檔案大小或是資料匣內所有檔案的大小總和

    12. 程式結束時自動將所有物件的狀態儲存在檔案裡

    13. 程式開始時自動由檔案中讀入上一次執行時各個物件的狀態: 請運用建構元函式實作

  2. 程式實作時請注意下列事項:

    1. 請運用 memory_leak.h, memory_leak.cpp 檢查記憶體的錯誤

    2. 下圖這個類別架構是一個非常常用的樣式 (pattern), 共有四個類別 Client, Component, Leaf 和 Composite, 我們稱為 Composite Pattern
    3. 這個樣式主要用來實作樹狀的資料架構, 其中 Composite 是樹狀架構內部的節點, 是一個容器, 一個 Composite 物件中可以再包含 Leaf 或是 Composite 物件, 我們稍微修改一下用來表示 File-Folder 的樹狀架構如下



    4. 其中每一個 File 類別的物件是樹狀架構中的葉節點 (Leaf node), 每一個 Folder 類別的物件是樹狀架構中的內部節點 (Internal node), 這兩種物件都有一個共同的特性就是它們都是上層節點的子節點, 因此我們把這種共同的架構歸納出來成為它們的父類別 Entry 類別。 Folder 類別的物件裡面需要記住其下層物件 (可以是 File 物件 或是 Folder 物件), 因此我們看到 Folder 類別可以和多個 Entry 類別的物件有關係, 圖中 Folder 類別旁邊中空的菱形是 UML 語法中代表聚合 Aggregation 的意思, 表示一個 Folder 裡可以容納多個 Entry, 同時所包含的 Entry 物件的生命週期和 Folder 沒有關係 (刪除 Folder 物件時, 不見得一定要刪除所有容納的物件, 例如可以將所容納的物件移到其他資料匣下, 這個搬移的功能在這次作業裡沒有要求你完成)。

    5. 在上面的架構裡, Folder 類別中的 entries 物件成員 是一個異質的陣列, 請注意很多搜尋與列印的動作中, 都會運用到 Entry * 型態的多型指標, 將 File 和 Folder 類別的物件一視同仁, 以簡化處理的機制。

    6. 上圖中 File::add() 事實上應該什麼都不做, 只回傳 false, File::remove(Entry *) 也是這樣
      File::getSize() 回傳檔案的大小 (byte 數), Folder::getSize() 回傳所有下層檔案大小的總和
      File::printList(prefix:string, recursive:bool) 轉而呼叫 Entry::printName(prefix)
      Folder::printList(prefix:string, recursive:bool) 除了呼叫 Entry::printName(prefix)列印本身資料匣名稱之外, 如果recursive為 true 的話, 還會要求子資料匣內所有的 Entry 物件列印
      prefix 字串最主要是用來調整列印時左邊應該保留的空格
      Folder::remove(Entry *=0) 這個介面 overload 兩個不同的用法, 如果呼叫 folderObject.remove(&fileObject) 則在該 folderObject 中刪除指定的 fileObject, 如果呼叫 folderObject.remove() 沒有給參數時, 就把 folderObject裡所有的物件(檔案或是資料匣)通通刪除
      另外建立樹狀架構時也可以考慮在上下層 folder 之間建立雙向的連結, 如此在遊走於各個資料匣時會比較方便

    7. 你可以參考在這幾個類別圖中我所列的界面函式來實作, 不過只實作這幾個界面函式可能也沒辦法完成程式的所有功能, 並不強迫你使用這樣子的界面, 如果你有更好的介面, 你覺得變更設計以後可以有比較好的設計, 一定要在心得裡面討論。

  3. 書面報告之要求:

    1. 基本的心得, 程式架構說明

    2. 請特別分析一下你的程式裡是否有不斷重複的程式架構, 有沒有什麼辦法簡化

進一步增加程式的功能

原則上你想要增加什麼功能都是可以的, 記得在心得中寫出來, 這樣助教才會注意到, 可以多得到一些分數, 例如移動檔案, 移動子資料匣, 複製檔案與資料匣, 檔案名稱排序等等。

程式繳交說明:

  1. 請於時限內 (98/05/20 星期三 24:00) 上傳程式檔案 (逾時無法上傳), 上傳網頁
  2. 請運用 StarUML 繪製 類別圖 將影像匯入 word 報告檔中, 並且繳交 .uml 檔案
  3. 此次程式你可以不需要列印所有的程式碼, 選擇有代表性的程式碼列印, 或是配合心得, 列印你自己覺得有問題, 需要討論的程式碼就可以了
  4. 程式設計心得與討論 (當然如果你沒有列印任何程式碼, 沒有討論任何程式碼, 沒有什麼有建設性的心得, 就算你有一個可以執行的程式, 你這一部份的分數可能還是很低 ) ,由於大家在期中考的表現裡顯示沒有用太多心思在作業和實習上,如此你也一定沒有辦法學到什麼東西,唸資訊工程系最大的優點其實就是你能夠由系統實作的角度來看任何問題,如果你放棄掌握軟體這個工具,那你在畢業的時候就會發現你在理論上比不上數學/應數系的訓練,在人機介面、通訊系統、數位硬體等等工程應用上比不上電機系的訓練,在經濟、會計、管理比不上資管系的訓練,你會變成很容易被人取代的...請加油

程式 Demo 說明:

  1. 抽中 demo 的同學,程式必須能夠現場編譯沒有錯誤
  2. 請說明你的測試方法與測試資料,並操作測試, 請將你要測試的資料先打好,例如 prog5a.in, 利用 DOS 的重新導向來測試,例如 prog5_v1 < prog5a.in > result.log
  3. 執行助教指定的測試資料
  4. 請回答你的程式在設計上的相關問題

C++ 程式設計課程 首頁

製作日期: 5/11/2009 by 丁培毅 (Pei-yih Ting)
E-mail: pyting@cs.ntou.edu.tw TEL: 02 24622192x6615
海洋大學 電機資訊學院 資訊工程系 Lagoon