Série: C++
cpp
348 linhas
· Atualizado 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;
}
Artigos relacionados
C++
c
Atualizado 2026-07-21
deviceAlpha.h
deviceAlpha.h — c source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/deviceAlpha.h).
Ler artigo →
C++
c
Atualizado 2026-07-21
finalproject.c
finalproject.c — c source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/finalproject.c).
Ler artigo →
C++
cpp
Atualizado 2026-07-21
finalproject.cpp
finalproject.cpp — cpp source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/finalproject.cpp).
Ler artigo →
C++
c
Atualizado 2026-07-21
deviceAlpha.h
deviceAlpha.h — c source code from the C++ learning materials (C++/Mavis_Homework/Lab8/deviceAlpha.h).
Ler artigo →
C++
c
Atualizado 2026-07-21
lab8.c
lab8.c — c source code from the C++ learning materials (C++/Mavis_Homework/Lab8/lab8.c).
Ler artigo →
C++
cpp
Atualizado 2026-07-21
lab8.cpp
lab8.cpp — cpp source code from the C++ learning materials (C++/Mavis_Homework/Lab8/lab8.cpp).
Ler artigo →