許多初學者習慣用面向過程的風格編寫 C++ 代碼,但隨著項目規模增長,面向對象(OOP)的封裝、繼承、多態特性能顯著提升代碼的可維護性與擴展性。本文以一個「單項選擇題標準化考試系統」為例,演示如何將傳統的結構體鏈表實現重構為標準的 C++ 類設計。
原代碼使用 struct question 形成單鏈表,所有操作(菜單、插入、查找、文件讀寫、答題邏輯)均為全局函數,數據與行為分離,存在全局變量污染、內存管理手動麻煩等問題。
將 question 結構體作為內部節點,由 ExamSystem 類管理鏈表頭指針 head,對外隱藏實現細節:
class ExamSystem {
private:
struct Node {
char ask[200];
char answer[4][80];
int right;
Node* next;
Node() : next(nullptr) {}
};
Node* head;
size_t count; // 題目總數
public:
ExamSystem() : head(nullptr), count(0) {}
~ExamSystem() { clear(); }
// 公開介面...
};
addQuestion(const Node&),內部處理頭插法並更新 count。getRandomStart(size_t n),利用 std::mt19937 替代 rand() 獲得更好隨機性。loadFromFile(FILE*) 和 saveToFile(FILE*),構造/析構時自動調用。inputQuestion()、inputAnswer()、getUserAnswer()、evaluate(size_t n)。使用 std::unique_ptr 或手動實現析構函數 clear() 釋放鏈表內存,避免洩漏;文件操作改用 std::fstream;輸入處理改用 std::getline 解決空格截斷問題。
| 原問題 | 重構方案 |
|---|---|
手動 malloc/free 易出錯 | 構造/析構函數自動管理生命周期 |
全局狀態 start, line | 封裝為類私有成員 |
scanf("%s") 無法讀取含空格標題 | std::getline(cin, str) 完整讀取行 |
隨機數 srand/rand 質量差 | <random> 引擎與分佈 |
| 答案統計邏輯與鏈表遍歷耦合 | 分離為獨立評估方法,可單元測試 |
int main() {
ExamSystem exam;
exam.loadFromFile("kstm.dat");
cout << "***** 歡迎使用考試系統 *****\n";
while (true) {
switch (exam.showMenu()) {
case 1: exam.inputQuestion(); break;
case 2: exam.startQuiz(); break;
case 3: exam.saveToFile("kstm.dat"); return 0;
}
}
}
通過面向對象重構,系統獲得了清晰的模塊邊界、自動資源管理、更安全的輸入處理與現代 C++ 風格。這不僅是語法轉換,更是設計思維的升級——將「數據+操作」封裝為有職責的對象,為後續擴展(如多題型、統計分析、GUI)奠定基礎。