108 年 國立中央大學土木工程學系碩士班:防災與資訊應用組《程式語言》
第 1 題10 分
以下各題,可用任一種物件導向程式語言撰寫/示範:
- 請說明類別與物件的相異與相同之處。
登入後即可作答並保存紀錄。
這題主要考查物件導向程式設計 (Object-Oriented Programming, OOP) 的基本概念:類別 (Class) 與物件 (Object) 的區別與關聯。
核心觀念:
類別是藍圖或模板,定義了物件的屬性 (attributes) 和行為 (methods)。
物件是類別的實例 (instance),是類別所描述事物的具體表現。
詳解:
-
相同之處 (Similarities):
- 關聯性 (Relationship): 物件是根據類別所建立的,類別是物件的定義。沒有類別,就無法創建物件。
- 封裝 (Encapsulation): 類別可以封裝資料 (屬性) 和操作這些資料的方法,而物件則繼承了這種封裝的特性,將資料與行為綁定在一起。
-
相異之處 (Differences):
- 性質 (Nature):
- 類別 (Class): 是一個抽象的藍圖、模板或概念。它描述了一組具有相同屬性和行為的物件的共同特徵。類別本身不佔用記憶體來儲存具體數據。
- 物件 (Object): 是類別的一個具體實例。它在記憶體中有實際的儲存空間,用來儲存其自身的屬性值。一個類別可以有多個物件實例。
- 存在形式 (Existence):
- 性質 (Nature):
第 2 題10 分
以下各題,可用任一種物件導向程式語言撰寫/示範:
2. 請說明編譯器與解譯器的相異與相同之處。
登入後即可作答並保存紀錄。
這題考查程式語言翻譯器的基本類型:編譯器 (Compiler) 與解譯器 (Interpreter)。
核心觀念:
編譯器將整個原始碼一次性翻譯成機器碼或中間碼,然後執行。
解譯器逐行讀取原始碼,翻譯並立即執行。
詳解:
-
相同之處 (Similarities):
- 目的 (Purpose): 兩者都是將人類可讀的程式碼 (原始碼,Source Code) 轉換成電腦可以理解和執行的形式 (機器碼,Machine Code 或其他中間形式)。
- 基本步驟 (Basic Steps): 都涉及詞法分析 (Lexical Analysis)、語法分析 (Syntax Analysis)、語義分析 (Semantic Analysis) 等階段,以理解原始碼的結構和意義。
-
相異之處 (Differences):
- 翻譯方式 (Translation Method):
- 編譯器 (Compiler): 在程式執行之前,將整個原始碼一次性翻譯成目標程式 (通常是機器碼或位元組碼)。翻譯完成後,生成一個獨立的可執行檔。
- 解譯器 (Interpreter): 逐行或逐個語句地讀取原始碼,並立即將其翻譯並執行。它不生成獨立的可執行檔。
- 執行過程 (Execution Process):
- 編譯器: 翻譯階段和執行階段是分開的。先編譯,生成可執行檔,然後再執行該檔。
- 解譯器: 翻譯和執行是交織在一起的,通常在執行時即時進行。
- 翻譯方式 (Translation Method):
第 3 題10 分
以下各題,可用任一種物件導向程式語言撰寫/示範:
3. 請說明建構函數的意義與用法。
登入後即可作答並保存紀錄。
這題考查物件導向程式設計中,類別的建構函數 (Constructor) 的概念。
核心觀念:
建構函數是一種特殊的成員函數,用於在創建類別物件時進行初始化。
詳解:
-
意義 (Meaning):
建構函數的主要意義和目的有:- 物件初始化 (Object Initialization): 在物件被建立的瞬間,自動執行,負責設定物件的初始狀態。這包括為物件的成員變數 (屬性) 賦予初始值。
- 資源配置 (Resource Allocation): 有時用於配置物件運行所需的資源,例如開啟檔案、建立資料庫連線、分配記憶體等。
- 確保物件有效性 (Ensuring Object Validity): 通過初始化,確保物件在創建後即處於一個有效、可用的狀態。
-
用法 (Usage):
- 命名規則 (Naming Convention): 在許多物件導向語言中(如 C++, Java, C#),建構函數的名稱必須與類別名稱完全相同。在 Python 中,建構函數是
__init__方法。 - 自動調用 (Automatic Invocation): 當使用
new關鍵字(或其他類似的物件創建機制)創建一個類別的物件時,建構函數會被自動調用,無需顯式調用。 - 參數 (Parameters): 建構函數可以帶參數,允許在創建物件時傳遞不同的值來初始化物件,從而創建不同狀態的物件。
- 多個建構函數 (Multiple Constructors): 某些語言(如 Java, C#)支援多個建構函數(方法重載),它們具有不同的參數列表,提供了多種創建物件的方式。
- 無傳回值 (No Return Value): 建構函數沒有傳回值,甚至連
void(在 C++ 中) 也不需要標示。它的任務是初始化物件,而不是傳回一個值。
- 命名規則 (Naming Convention): 在許多物件導向語言中(如 C++, Java, C#),建構函數的名稱必須與類別名稱完全相同。在 Python 中,建構函數是
-
範例 (Example - C++):
第 4 題10 分
以下各題,可用任一種物件導向程式語言撰寫/示範:
4. 請說明解構函數的意義與用法。
登入後即可作答並保存紀錄。
這題考查物件導向程式設計中,類別的解構函數 (Destructor) 的概念。
核心觀念:
解構函數是一種特殊的成員函數,用於在物件被銷毀時進行清理工作,釋放物件所佔用的資源。
詳解:
-
意義 (Meaning):
解構函數的主要意義和目的有:- 資源釋放 (Resource Deallocation): 在物件生命週期結束、即將被系統回收記憶體之前,自動執行,負責釋放物件在建構時獲取的資源。這包括關閉檔案、釋放動態分配的記憶體、關閉網路連線、釋放鎖定等。
- 防止資源洩漏 (Preventing Resource Leaks): 確保所有佔用的資源都能被正確釋放,避免因資源未釋放而導致的程式運行問題(如記憶體洩漏)。
- 物件清理 (Object Cleanup): 執行任何必要的清理操作,以確保程式的穩定性。
-
用法 (Usage):
- 命名規則 (Naming Convention): 在 C++ 中,解構函數的名稱是波浪號 (
~) 後跟著類別名稱(例如~MyClass())。在 Java 或 Python 等有自動記憶體管理的語言中,通常沒有顯式的解構函數,而是由垃圾回收機制 (Garbage Collector) 處理資源釋放(但仍有類似的機制,如 Python 的__del__方法,但其行為與 C++ 的解構函數不完全相同,且不保證立即執行)。 - 自動調用 (Automatic Invocation): 當物件的生命週期結束時(例如,離開其作用域、程式結束、或被顯式刪除),解構函數會被自動調用。
- 無參數 (No Parameters): 解構函數不能帶參數。
- 無傳回值 (No Return Value): 解構函數沒有傳回值,不需要標示
void。 - 一個類別只有一個解構函數 (One Destructor per Class): 一個類別只能有一個解構函數。
- 命名規則 (Naming Convention): 在 C++ 中,解構函數的名稱是波浪號 (
-
範例 (Example - C++):
第 5 題10 分
以下各題,可用任一種物件導向程式語言撰寫/示範:
5. 請說明指定運算子的意義與用法。
登入後即可作答並保存紀錄。
這題考查程式語言中的指定運算子 (Assignment Operator)。
核心觀念:
指定運算子用於將一個值賦予給一個變數。
詳解:
-
意義 (Meaning):
指定運算子 (=) 是程式語言中最基本且最重要的運算子之一。它的主要作用是將運算子右側表達式 (expression) 的計算結果,儲存到運算子左側的變數 (variable) 中。這個過程稱為「賦值」或「指定」。 -
用法 (Usage):
- 基本語法 (Basic Syntax):
variable = expression;variable: 必須是一個可寫入的目標(左值,lvalue),通常是變數、陣列元素、物件的成員變數等。expression: 可以是一個常數、另一個變數、或任何能計算出一個值的表達式。
- 值的傳遞 (Value Transfer): 指定運算子將
expression的值複製到variable中。對於基本資料型別 (如整數、浮點數、布林值),這是值的直接複製。對於複合資料型別(如物件、陣列),其行為可能依語言而異,可能是複製值(淺複製或深複製),也可能是複製參考 (reference)。 - 連續指定 (Chained Assignment): 在許多語言中,可以進行連續指定,例如
a = b = c = 10;。這表示c被賦值為10,然後b被賦值為c的值(即10),最後a被賦值為b的值(即10)。這通常是從右向左執行的。 - 複合指定運算子 (Compound Assignment Operators): 為了方便和簡潔,許多語言提供了複合指定運算子,它們結合了算術運算或位元運算與指定運算。常見的有:
+=(加並指定):x += y等同於x = x + y-=(減並指定):x -= y等同於x = x - y*=(乘並指定):x *= y等同於x = x * y/=(除並指定):x /= y等同於x = x / y%=(取餘並指定):x %= y等同於x = x % y
- 基本語法 (Basic Syntax):
第 6 題10 分
以下各題,可用任一種物件導向程式語言撰寫/示範:
6. 請說明 operator overloading的意義與用法。
登入後即可作答並保存紀錄。
這題考查物件導向程式設計中,運算子重載 (Operator Overloading) 的概念。
核心觀念:
運算子重載允許我們為使用者自訂的資料型別 (如類別) 定義運算子的行為,使其能夠像內建型別一樣直觀地使用。
詳解:
-
意義 (Meaning):
運算子重載的目的是讓使用者定義的類型(例如,一個表示複數的類別、一個表示向量的類別、或一個表示大數的類別)能夠使用標準的運算符號(如+,-,*,/,==,<<,>>等)來進行運算。這使得程式碼更具可讀性和表達力,讓使用者能夠以更接近數學或邏輯的方式來操作這些自訂型別的物件,而無需調用特定的方法名(如add(obj1, obj2))。 -
用法 (Usage):
- 實現方式 (Implementation): 運算子重載通常是通過定義特殊的成員函數或非成員函數來實現的。這些函數的名稱或簽名會與要重載的運算子相關聯。
- 成員函數 (Member Function): 函數作為類別的成員,第一個參數是隱式的
this指標(代表左側運算元),其他參數則是右側的運算元。 - 非成員函數 (Non-member Function): 函數不是類別的成員,所有運算元都需要作為參數傳遞。這對於重載單元運算子(如一元
+、-)或需要交換運算元順序(例如,允許5 + Vector而非僅Vector + 5)的情況很有用。
- 成員函數 (Member Function): 函數作為類別的成員,第一個參數是隱式的
- 語法 (Syntax): 具體的語法因語言而異。
- C++: 使用
operator關鍵字,後面跟著要重載的運算符號。// 類別定義 class MyNumber { public: int value; MyNumber(int v) : value(v) {} // 重載 + 運算子 (成員函數) MyNumber operator+(const MyNumber& other) const { return MyNumber(this->value + other.value); } // 重載 << 運算子 (非成員函數,需要是友元函數才能訪問 private 成員) friend std::ostream& operator<<(std::ostream& os, const MyNumber& num) { os << num.value; return os; } }; - Python: 通過定義特殊方法 (magic methods 或 dunder methods) 來實現,方法名稱以雙底線
__開頭和結尾。
- C++: 使用
- 實現方式 (Implementation): 運算子重載通常是通過定義特殊的成員函數或非成員函數來實現的。這些函數的名稱或簽名會與要重載的運算子相關聯。
第 7 題10 分
以下各題,可用任一種物件導向程式語言撰寫/示範:
7. 請舉例說明函數指標的用法。
登入後即可作答並保存紀錄。
這題考查函數指標 (Function Pointer) 的概念與用法。
核心觀念:
函數指標是一個變數,它儲存了函數的記憶體地址,因此可以通過該指標來調用函數。
詳解:
-
意義 (Meaning):
函數指標提供了一種間接調用函數的方式。它允許我們將函數作為參數傳遞給其他函數,或者將函數存儲在陣列或結構體中,從而實現更靈活的程式設計,例如回調函數 (callback functions)、策略模式 (strategy pattern) 等。 -
用法 (Usage):
-
宣告函數指標 (Declaring a Function Pointer):
函數指標的宣告語法需要指定函數的傳回值型別和參數型別。
語法:return_type (*pointer_name)(parameter_type1, parameter_type2, ...);
例如,一個指向函數,該函數接受兩個整數並傳回一個整數的指標:int (*funcPtr)(int, int); -
獲取函數地址 (Getting the Function Address):
函數的名稱本身就代表了它的地址。
例如,如果有一個函數int add(int a, int b) { return a + b; },則add就是該函數的地址。 -
將函數地址賦值給指標 (Assigning a Function Address to a Pointer):
將函數的名稱(即其地址)賦值給宣告好的函數指標。
funcPtr = add;(或funcPtr = &add;,&是可選的) -
通過函數指標調用函數 (Calling a Function through a Pointer):
有兩種方式:(*funcPtr)(arg1, arg2);(顯式解引用)funcPtr(arg1, arg2);(隱式解引用,更常用)
-
-
範例 (Example - C++):
假設我們要實現一個簡單的計算器,可以根據傳入的運算符號來執行加法或減法。
第 8 題10 分
以下各題,可用任一種物件導向程式語言撰寫/示範:
8. 請示範以二維指標配置整數矩陣(mn)的程式碼,整數為[0, mn)之間的亂數。
登入後即可作答並保存紀錄。
這題考查 C/C++ 中使用二維指標 (或指標的指標) 動態配置記憶體來建立一個二維陣列(矩陣),並填充隨機數。
核心觀念:
在 C/C++ 中,二維陣列的動態配置通常有兩種方式:
- 使用指標的指標 (
int**),為每一列單獨配置記憶體。 - 使用單一指標,模擬二維陣列的存取 (較少見於此類題目)。
此題要求使用「二維指標」,通常指的是第一種方式。
詳解:
方法:使用指標的指標 (int**)
這種方法將二維陣列表示為一個指標的陣列,其中每個指標指向一維陣列(即矩陣的一行)。
- 配置指向指標的指標的記憶體: 首先,為
m個指標分配記憶體。這些指標將分別指向矩陣的每一行。 - 為每一行配置記憶體: 對於每個指標,再單獨為其分配
n個整數的記憶體,形成矩陣的一行。 - 填充隨機數: 遍歷整個矩陣,並為每個元素生成一個
[0, m*n)範圍內的隨機數並賦值。 - 釋放記憶體: 最後,需要按照分配的逆序釋放記憶體,先釋放每一行的記憶體,再釋放指向指標的指標的記憶體。
程式碼範例 (C++):
第 9 題10 分
以下各題,可用任一種物件導向程式語言撰寫/示範:
9. 承接第八題,請示範兩個整數矩陣相乘的程式碼。
登入後即可作答並保存紀錄。
這題要求實現兩個矩陣的乘法,並假設矩陣是通過題八的方法(使用 int** 指標)動態分配的。
核心觀念:
矩陣乘法要求第一個矩陣的列數必須等於第二個矩陣的行數。若矩陣 A 是 矩陣,矩陣 B 是 矩陣,則它們的乘積 C 是 矩陣,其中 C 的第 行第 列的元素 計算方式為:
詳解:
我們需要一個函數來執行矩陣乘法。這個函數將接收兩個矩陣、它們的維度,並返回一個新的矩陣作為乘積。
程式碼範例 (C++):
假設我們有兩個矩陣 matrixA (維度 ) 和 matrixB (維度 )。
矩陣乘法要求 。
結果矩陣 matrixC 的維度將是 。
第 10 題10 分
以下各題,可用任一種物件導向程式語言撰寫/示範:
10. 請說明物件導向程式語言的多型(polymorphism)概念。
登入後即可作答並保存紀錄。
這題考查物件導向程式設計 (OOP) 的核心概念之一:多型 (Polymorphism)。
核心觀念:
多型是指「一個名稱,多種形式」。在物件導向程式設計中,多型允許我們以統一的方式處理不同類型的物件,而無需知道它們的具體類型。
詳解:
-
意義 (Meaning):
多型(Polymorphism)源自希臘語,意為「多種形態」。在 OOP 中,它指的是一個介面 (interface) 或基底類別 (base class) 可以參考其衍生類別 (derived class) 的物件,並且在運行時 (runtime) 能夠根據物件的實際類型來調用相應的方法。簡而言之,就是「一個呼叫,多種行為」。 -
多型的種類:
- 編譯時期多型 (Compile-time Polymorphism) / 靜態多型 (Static Polymorphism):
- 在程式編譯時就確定了要調用的函數。
- 常見的實現方式包括:
- 函數重載 (Function Overloading): 允許存在多個名稱相同但參數列表不同(參數型別、數量或順序不同)的函數。編譯器根據傳入的參數來決定調用哪個函數。
- 運算子重載 (Operator Overloading): 如題 6 所述,為自訂型別定義運算符的行為。
- 運行時期多型 (Runtime Polymorphism) / 動態多型 (Dynamic Polymorphism):
- 在程式執行時才確定要調用的函數。這是 OOP 中多型最核心、最常見的應用。
- 通常通過虛函數 (Virtual Functions) 和繼承 (Inheritance) 來實現。
- 當通過基底類別的指標或參考調用一個虛函數時,系統會根據指標或參考實際指向的物件類型,動態地決定調用哪個衍生類別的實作。
- 編譯時期多型 (Compile-time Polymorphism) / 靜態多型 (Static Polymorphism):
-
實現運行時期多型的關鍵要素:
- 繼承 (Inheritance): 必須存在基底類別和衍生類別之間的繼承關係。
- 虛函數 (Virtual Functions): 基底類別中聲明為
virtual的函數,表示它可以在衍生類別中被重新定義 (override)。 - 物件指標或參考 (Object Pointers or References): 必須使用基底類別類型的指標或參考來指向或引用衍生類別的物件。
-
優點 (Benefits):
- 擴展性 (Extensibility): 可以輕鬆地添加新的衍生類別,而無需修改現有的使用基底類別介面的程式碼。
- 靈活性 (Flexibility): 程式設計師可以編寫更通用的程式碼,處理各種物件,而無需為每種特定類型編寫單獨的邏輯。
- 可維護性 (Maintainability): 簡化了程式結構,提高了程式碼的可讀性和可維護性。
-
範例 (Example - C++ using Virtual Functions):
考慮一個繪圖系統,我們可以繪製不同形狀的圖形。