C++ 入門指南 4.01

單元 12 - 建構函數

-unit12-

函數 (function) 可以有多個參數 (parameter) 版本,建構函數 (constructor) 亦同,具有多個參數版本的函數被稱為多載函數 (overloaded function)

建構函數 ⇉ 多載函數

為什麼會需要多載函數呢?這是因為多載函數可以處理不同型態的參數,例如我們需要一個將數字相加的函數

int a = add(12, 32);

兩個參數 1232 都是整數,運用之前 Demo::do_something() 的實作即可完成,那假如參數有一個不是整數呢?

double b = add(2.53, 32);

由於 C++ 是強型態 (strong typing) 的程式語言,浮點數的 double 與整數 int 是不同的資料型態 (data type) ,計算兩種資料型態前要先做型態轉換,不然就有可能會出現無法預期的結果

double add(double p_a, int p_b) {
    double c = (double) p_b;
    return p_a + c;
}

雖然編譯器會自動替基本內建型態 (primitive built-in type) 進行型態轉換,有些地方並不會出錯,可是有些地方就會出錯,保險一點就是我們養成型態轉換的習慣,只要型態不同,就自己加進轉換的程式碼。

多載函數的版本是依參數列中參數的數量與型態,函數只能有一個回傳值 (return value) ,若只有回傳值型態 (return type) 不同,這並不構成另一個多載函數。

建構函數的主要目的是設定資料成員 (data member) ,由於 Demo 有兩個資料成員 ab ,因此我們打算設置三種參數版本,分別是沒有參數、一個參數及兩個參數

Demo();
Demo(int);
Demo(int, int);

沒有參數的建構函數直接呼叫修改函數將 ab 都設定為整數 1 ,一個參數的建構函數將 ab 都設定為參數值,至於兩個參數的建構函數, a 設定為第一個參數, b 設定為第二個參數,實作如下

// 沒有參數的建構函數
Demo::Demo() {
    set_a(1);
    set_b(1);
}

// 一個參數的建構函數
Demo::Demo(int n1) {
    set_a(n1);
    set_b(n1);
}

// 兩個參數的建構函數
Demo::Demo(int n1, int n2) {
    set_a(n1);
    set_a(n1);
    set_b(n2);
}

寫成完整範例如下

#include <iostream>

using namespace std;

class Demo {
// 宣告 public 的成員
public:
    Demo();
    Demo(int n1);
    Demo(int n1, int n2);
    void set_a(int n);
    void set_b(int n);
    int get_a();
    int get_b();
    int DoSomething();

// 宣告 private 的成員
private:
    int a;
    int b;
};

// 沒有參數的建構函數
Demo::Demo() {
    set_a(1);
    set_b(1);
}

// 一個參數的建構函數
Demo::Demo(int n1) {
    set_a(n1);
    set_b(n1);
}

// 兩個參數的建構函數
Demo::Demo(int n1, int n2) {
    set_a(n1);
    set_b(n2);
}

int Demo::DoSomething() {
    // 改成呼叫 getter 成員函數
    return get_a() + get_b();
}

// setter 與 getter 成員函數
void Demo::set_a(int n) {
    a = n;
}

void Demo::set_b(int n) {
    b = n;
}

int Demo::get_a() {
    return a;
}

int Demo::get_b() {
    return b;
}

int main(void) {
    Demo t1;
    Demo t2(11);
    Demo t3(11, 22);

    cout << endl;
    cout << t1.DoSomething() << endl;
    cout << t2.DoSomething() << endl;
    cout << t3.DoSomething() << endl;
    cout << endl;

    return 0;
}

/* 《程式語言教學誌》的範例程式
   http://kaiching.org/
   檔名:class_demo3.cxx
   功能:示範定義類別
   作者:張凱慶 */

利用建構函數建立物件 (object) ,宣告變數 (variable) 時加小括弧即可,需要留意沒有參數的建構函數不需要加小括弧

Demo t1;
Demo t2(11);
Demo t3(11, 22);

編譯執行結果如下

-classdemo3-

我們連續介紹了物件導向程式設計 (object-oriented programming) 中的封裝 (encapsulation) 與建構函數,接下來還有個寫 C++ 程式基本並且重要的主題,也就是設計專屬的標頭檔 (header file) ,下面我們繼續討論囉!

中英文術語對照
建構函數constructor
資料成員data member
資料型態data type
封裝encapsulation
函數function
標頭檔header file
物件object
物件導向程式設計object-oriented programming
多載函數overloaded function
參數parameter
基本內建型態primitive built-in type
回傳值型態return type
回傳值return value
強型態strong typing
變數variable
重點整理
1. 具有多個參數版本的函數被稱為多載函數,也就是允許函數有不同的參數列。
2. C++ 是強型態的程式語言,運算式中若有兩種不同的資料型態,就需要先進行型態轉換。
3. 編譯器會替基本內建型態進行自動型態轉換。
4. 函數只能有一個回傳值,若只有回傳值型態不同,這並不構成另一個多載函數。
5. 建構函數的主要目的是設定變數成員。
問題與討論
1. 為什麼兩個函數只有回傳值型態的不同,並不構成多載函數?
2. 為什麼編譯器要替基本內建型態進行自動型態轉換?
3. 建構函數的用途為何?除了設定變數成員外,建構函數還有其他功能嗎?
練習
1. 寫一個程式 exercise1201.cxx ,利用 exercise1102.cxx 設計的 IntegerDemo ,加入兩個建構函數,第一個建構函數沒有參數,將 value 預設為 0 ,第二個建構函數利用參數設定 value ,然後把 set_value(int) 移到 private 標籤之下。 參考程式碼
2. 寫一個程式 exercise1202.cxx ,利用 exercise1103.cxx 計算階層值的類別,將 Compute() 的內容移到 set_value(int) 之內,然後利用建構函數呼叫 set_value(int) ,注意建構函數需要一個參數,然後把 set_value(int) 移到 private 標籤之下。 參考程式碼
3. 寫一個程式 exercise1203.cxx ,利用 exercise1104.cxx 計算費氏數列的類別,將 Compute() 的內容移到 set_value(int) 之內,然後利用建構函數呼叫 set_value(int) ,注意建構函數需要一個參數,然後把 set_value(int) 移到 private 標籤之下。 參考程式碼
4. 寫一個程式 exercise1204.cxx ,利用 exercise1105.cxxPoint 類別,加入建構函數呼叫修改函數設定 xy 成員變數,增加 get_point() 回傳座標的字串形式,然後印出兩點座標及距離。 參考程式碼
5. 寫一個程式 exercise1205.cxx ,利用 exercise1106.cxxGuess 類別,然後利用建構函數呼叫 set_a(string) ,注意建構函數需要一個參數,然後把 set_a(string) 移到 private 標籤之下。 參考程式碼
6. 寫一個程式 exercise1206.cxx ,利用 exercise1107.cxxMember 類別,加入建構函數呼叫 set_id(int)set_name(string) ,並把這兩個成員函數移到 private 標籤之下。 參考程式碼
7. 寫一個程式 exercise1207.cxx ,利用 exercise1108.cxxText 類別,然後利用建構函數呼叫 set_c(string) ,注意建構函數需要一個參數,然後把 set_c(string) 移到 private 標籤之下。 參考程式碼
8. 寫一個程式 exercise1208.cxx ,利用 exercise1109.cxxBall 類別,注意除了 Point 用上面 exercise1204.cxx 加入建構函數外, Ball 也加入建構函數,相關修改函數都移到 private 標籤之下。 參考程式碼
9. 寫一個程式 exercise1209.cxx ,利用 exercise1110.cxxScene 類別,加入建構函數呼叫修改函數設定 idtext 成員變數,然後利用建構函數呼叫 set_id(int)set_text(string) ,注意建構函數需要兩個參數,然後把兩個修改函數移到 private 標籤之下。 參考程式碼
10. 寫一個程式 exercise1210.cxx ,利用 exercise1111.cxxBall 類別,注意除了 GuessBall 用上面練習加入建構函數外, Game 也加入建構函數,相關修改函數都移到 private 標籤之下。 參考程式碼

相關教學影片

上一頁 單元 11 - 物件導向與封裝
回 C++ 入門指南 4.01 目錄
下一頁 單元 13 - 設計專屬的標頭檔
回 C++ 教材
回程式語言教材首頁