S SmartDocs
Series: C++ cpp 348 lines · Updated 2026-04-03

abstract_class.cpp

C++/Part2_物件導向/Ch10_繼承與多型/abstract_class.cpp

// ============================================================
// Ch10 — abstract_class.cpp
// 抽象類別:純虛擬函式、介面設計、final、dynamic_cast、typeid
// 編譯:g++ -std=c++17 -Wall -o abstract_class abstract_class.cpp
// ============================================================

#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <typeinfo>

// ────────────────────────────────────────────────────────────
// 1. 抽象類別 — Vehicle 介面
//    純虛擬函式 (= 0) 使類別無法被實例化
// ────────────────────────────────────────────────────────────

class Vehicle {
public:
    virtual void start() const = 0;
    virtual void stop() const = 0;
    virtual std::string type() const = 0;
    virtual int maxSpeed() const = 0;

    // 非純虛擬:提供預設實作
    virtual void honk() const {
        std::cout << "  嗶嗶!\n";
    }

    virtual ~Vehicle() = default;

    void describe() const {
        std::cout << "  [" << type() << "] 最高時速: "
                  << maxSpeed() << " km/h\n";
    }
};

class Car : public Vehicle {
public:
    Car(const std::string& brand) : brand_(brand) {}

    void start() const override {
        std::cout << "  " << brand_ << " 汽車發動引擎 🚗\n";
    }

    void stop() const override {
        std::cout << "  " << brand_ << " 汽車熄火\n";
    }

    std::string type() const override { return "汽車 - " + brand_; }
    int maxSpeed() const override { return 200; }

    void honk() const override {
        std::cout << "  叭叭!(" << brand_ << ")\n";
    }

private:
    std::string brand_;
};

class Bicycle : public Vehicle {
public:
    void start() const override {
        std::cout << "  腳踏車開始踩踏 🚲\n";
    }

    void stop() const override {
        std::cout << "  腳踏車煞車\n";
    }

    std::string type() const override { return "腳踏車"; }
    int maxSpeed() const override { return 40; }

    // honk() 使用預設實作
};

class ElectricScooter final : public Vehicle {
    // final:不允許再被繼承
public:
    void start() const override {
        std::cout << "  電動滑板車啟動 🛴\n";
    }

    void stop() const override {
        std::cout << "  電動滑板車關閉電源\n";
    }

    std::string type() const override { return "電動滑板車"; }
    int maxSpeed() const override { return 25; }
};

// 若嘗試繼承 final 類別,會編譯錯誤:
// class SuperScooter : public ElectricScooter {};  // ← 錯誤!

// ────────────────────────────────────────────────────────────
// 2. 介面設計模式 — Printable 與 Serializable
// ────────────────────────────────────────────────────────────

class Printable {
public:
    virtual void print(std::ostream& os) const = 0;
    virtual ~Printable() = default;
};

class Serializable {
public:
    virtual std::string serialize() const = 0;
    virtual ~Serializable() = default;
};

// Document 同時實作兩個介面(多重繼承介面)
class Document : public Printable, public Serializable {
public:
    Document(const std::string& title, const std::string& content)
        : title_(title), content_(content) {}

    void print(std::ostream& os) const override {
        os << "  ┌─────────────────────────┐\n"
           << "  │ 文件: " << title_ << "\n"
           << "  │ 內容: " << content_ << "\n"
           << "  └─────────────────────────┘\n";
    }

    std::string serialize() const override {
        return "{\"title\":\"" + title_ + "\",\"content\":\"" + content_ + "\"}";
    }

private:
    std::string title_;
    std::string content_;
};

// ────────────────────────────────────────────────────────────
// 3. dynamic_cast 與 typeid 示範
// ────────────────────────────────────────────────────────────

class Animal {
public:
    Animal(const std::string& name) : name_(name) {}
    virtual void speak() const = 0;
    virtual ~Animal() = default;

    const std::string& name() const { return name_; }

protected:
    std::string name_;
};

class DogAnimal : public Animal {
public:
    DogAnimal(const std::string& name) : Animal(name) {}

    void speak() const override {
        std::cout << "  " << name_ << " 說:汪汪!\n";
    }

    void fetch() const {
        std::cout << "  " << name_ << " 去撿球了!\n";
    }
};

class CatAnimal : public Animal {
public:
    CatAnimal(const std::string& name) : Animal(name) {}

    void speak() const override {
        std::cout << "  " << name_ << " 說:喵喵!\n";
    }

    void purr() const {
        std::cout << "  " << name_ << " 在呼嚕呼嚕~\n";
    }
};

class BirdAnimal : public Animal {
public:
    BirdAnimal(const std::string& name) : Animal(name) {}

    void speak() const override {
        std::cout << "  " << name_ << " 說:啾啾!\n";
    }

    void fly() const {
        std::cout << "  " << name_ << " 展翅高飛!\n";
    }
};

// ────────────────────────────────────────────────────────────
// 4. 衍生類別未完全實作純虛擬函式 → 仍為抽象類別
// ────────────────────────────────────────────────────────────

class AbstractWorker {
public:
    virtual void doWork() const = 0;
    virtual void report() const = 0;
    virtual ~AbstractWorker() = default;
};

// 只實作了一個,仍為抽象類別
class PartialWorker : public AbstractWorker {
public:
    void doWork() const override {
        std::cout << "  PartialWorker 工作中...\n";
    }
    // report() 未實作 → PartialWorker 仍是抽象類別
};

// 完整實作
class FullWorker : public PartialWorker {
public:
    void report() const override {
        std::cout << "  FullWorker 報告完成!\n";
    }
};

// ============================================================
// main
// ============================================================

int main() {
    std::cout << "========================================\n";
    std::cout << " 1. 抽象類別 Vehicle 與多型\n";
    std::cout << "========================================\n";
    {
        // Vehicle v;  // ← 編譯錯誤!無法實例化抽象類別

        std::vector<std::unique_ptr<Vehicle>> fleet;
        fleet.push_back(std::make_unique<Car>("Toyota"));
        fleet.push_back(std::make_unique<Car>("BMW"));
        fleet.push_back(std::make_unique<Bicycle>());
        fleet.push_back(std::make_unique<ElectricScooter>());

        for (const auto& v : fleet) {
            v->describe();
            v->start();
            v->honk();
            v->stop();
            std::cout << "\n";
        }
    }

    std::cout << "========================================\n";
    std::cout << " 2. 介面:Printable + Serializable\n";
    std::cout << "========================================\n";
    {
        Document doc("C++ 教學", "繼承與多型入門");

        // 透過 Printable 介面
        Printable* p = &doc;
        p->print(std::cout);

        // 透過 Serializable 介面
        Serializable* s = &doc;
        std::cout << "  序列化: " << s->serialize() << "\n\n";
    }

    std::cout << "========================================\n";
    std::cout << " 3. dynamic_cast 安全向下轉型\n";
    std::cout << "========================================\n";
    {
        std::vector<std::unique_ptr<Animal>> animals;
        animals.push_back(std::make_unique<DogAnimal>("小黑"));
        animals.push_back(std::make_unique<CatAnimal>("小花"));
        animals.push_back(std::make_unique<DogAnimal>("Lucky"));
        animals.push_back(std::make_unique<BirdAnimal>("小鳥"));
        animals.push_back(std::make_unique<CatAnimal>("咪咪"));

        std::cout << "\n--- 所有動物 speak() ---\n";
        for (const auto& a : animals) {
            a->speak();
        }

        std::cout << "\n--- 用 dynamic_cast 找出所有 Dog 並 fetch() ---\n";
        for (const auto& a : animals) {
            // 嘗試轉型為 DogAnimal*
            DogAnimal* dog = dynamic_cast<DogAnimal*>(a.get());
            if (dog) {
                dog->fetch();
            }
        }

        std::cout << "\n--- 用 dynamic_cast 找出所有 Cat 並 purr() ---\n";
        for (const auto& a : animals) {
            CatAnimal* cat = dynamic_cast<CatAnimal*>(a.get());
            if (cat) {
                cat->purr();
            }
        }

        std::cout << "\n--- 用 dynamic_cast 找出所有 Bird 並 fly() ---\n";
        for (const auto& a : animals) {
            BirdAnimal* bird = dynamic_cast<BirdAnimal*>(a.get());
            if (bird) {
                bird->fly();
            }
        }
    }

    std::cout << "\n========================================\n";
    std::cout << " 4. typeid 執行期型別資訊\n";
    std::cout << "========================================\n";
    {
        std::unique_ptr<Animal> a1 = std::make_unique<DogAnimal>("阿旺");
        std::unique_ptr<Animal> a2 = std::make_unique<CatAnimal>("阿貓");

        // typeid 透過多型取得實際型別
        Animal& ref1 = *a1;
        Animal& ref2 = *a2;
        std::cout << "  a1 的型別: " << typeid(ref1).name() << "\n";
        std::cout << "  a2 的型別: " << typeid(ref2).name() << "\n";

        // 比較型別
        if (typeid(ref1) == typeid(DogAnimal)) {
            std::cout << "  a1 確實是 DogAnimal!\n";
        }

        if (typeid(ref1) != typeid(ref2)) {
            std::cout << "  a1 和 a2 是不同型別\n";
        }
    }

    std::cout << "\n========================================\n";
    std::cout << " 5. 部分實作的抽象類別\n";
    std::cout << "========================================\n";
    {
        // PartialWorker pw;  // ← 編譯錯誤!仍是抽象類別
        FullWorker fw;
        fw.doWork();
        fw.report();
    }

    std::cout << "\n========================================\n";
    std::cout << " 6. final 關鍵字\n";
    std::cout << "========================================\n";
    {
        ElectricScooter es;
        es.describe();
        es.start();
        es.stop();
        std::cout << "  (ElectricScooter 標記為 final,無法再被繼承)\n";
    }

    std::cout << "\n========================================\n";
    std::cout << " 程式結束\n";
    std::cout << "========================================\n";

    return 0;
}

Related articles