Serie: C++
cpp
273 líneas
· Actualizado 2026-04-03
polymorphism.cpp
C++/Part2_物件導向/Ch10_繼承與多型/polymorphism.cpp
// ============================================================
// Ch10 — polymorphism.cpp
// 多型:虛擬函式、vtable 概念、虛擬解構子、override、
// 基礎類別指標指向衍生物件的執行期多型
// 編譯:g++ -std=c++17 -Wall -o polymorphism polymorphism.cpp
// ============================================================
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <cmath>
// ────────────────────────────────────────────────────────────
// 1. Shape 階層 — 完整的多型示範
// ────────────────────────────────────────────────────────────
class Shape {
public:
Shape(const std::string& name) : name_(name) {}
// 虛擬函式:衍生類別可以覆寫
virtual double area() const { return 0.0; }
virtual double perimeter() const { return 0.0; }
virtual void draw() const {
std::cout << " [Shape] 繪製 " << name_ << "\n";
}
// 虛擬解構子:確保透過基礎類別指標 delete 時正確解構
virtual ~Shape() {
std::cout << " [~Shape] " << name_ << "\n";
}
const std::string& name() const { return name_; }
protected:
std::string name_;
};
// ── Circle ──
class Circle : public Shape {
public:
Circle(double radius)
: Shape("圓形"), radius_(radius) {}
double area() const override {
return M_PI * radius_ * radius_;
}
double perimeter() const override {
return 2.0 * M_PI * radius_;
}
void draw() const override {
std::cout << " ● 繪製圓形 (半徑=" << radius_ << ")\n";
}
~Circle() override {
std::cout << " [~Circle] 半徑=" << radius_ << "\n";
}
private:
double radius_;
};
// ── Rectangle ──
class Rectangle : public Shape {
public:
Rectangle(double w, double h)
: Shape("長方形"), width_(w), height_(h) {}
double area() const override {
return width_ * height_;
}
double perimeter() const override {
return 2.0 * (width_ + height_);
}
void draw() const override {
std::cout << " ▬ 繪製長方形 (" << width_
<< " x " << height_ << ")\n";
}
~Rectangle() override {
std::cout << " [~Rectangle] " << width_ << "x" << height_ << "\n";
}
private:
double width_, height_;
};
// ── Triangle ──
class Triangle : public Shape {
public:
Triangle(double a, double b, double c)
: Shape("三角形"), a_(a), b_(b), c_(c) {}
double area() const override {
// 海龍公式
double s = (a_ + b_ + c_) / 2.0;
return std::sqrt(s * (s - a_) * (s - b_) * (s - c_));
}
double perimeter() const override {
return a_ + b_ + c_;
}
void draw() const override {
std::cout << " △ 繪製三角形 (邊長: "
<< a_ << ", " << b_ << ", " << c_ << ")\n";
}
~Triangle() override {
std::cout << " [~Triangle]\n";
}
private:
double a_, b_, c_;
};
// ────────────────────────────────────────────────────────────
// 2. 虛擬解構子對比實驗
// ────────────────────────────────────────────────────────────
class BaseNoVirtual {
public:
BaseNoVirtual() { std::cout << " [BaseNoVirtual] 建構\n"; }
~BaseNoVirtual() { std::cout << " [BaseNoVirtual] 解構\n"; }
// ↑ 非虛擬解構子
};
class DerivedNoVirtual : public BaseNoVirtual {
public:
DerivedNoVirtual() { std::cout << " [DerivedNoVirtual] 建構\n"; }
~DerivedNoVirtual() { std::cout << " [DerivedNoVirtual] 解構\n"; }
};
class BaseVirtual {
public:
BaseVirtual() { std::cout << " [BaseVirtual] 建構\n"; }
virtual ~BaseVirtual() { std::cout << " [BaseVirtual] 解構\n"; }
};
class DerivedVirtual : public BaseVirtual {
public:
DerivedVirtual() { std::cout << " [DerivedVirtual] 建構\n"; }
~DerivedVirtual() override { std::cout << " [DerivedVirtual] 解構\n"; }
};
// ────────────────────────────────────────────────────────────
// 3. 展示 override 防止拼字錯誤
// ────────────────────────────────────────────────────────────
class Instrument {
public:
virtual void play() const { std::cout << " ♪ Instrument 演奏\n"; }
virtual ~Instrument() = default;
};
class Piano : public Instrument {
public:
void play() const override { std::cout << " ♫ Piano 演奏鋼琴曲\n"; }
// 若寫成 void Play() const override → 編譯錯誤!拼字錯誤被抓到
};
class Violin : public Instrument {
public:
void play() const override { std::cout << " ♫ Violin 演奏小提琴曲\n"; }
};
// ============================================================
// main
// ============================================================
int main() {
std::cout << "========================================\n";
std::cout << " 1. 基礎類別指標的多型行為\n";
std::cout << "========================================\n";
{
// 使用 unique_ptr 管理記憶體,基礎類別有虛擬解構子
std::vector<std::unique_ptr<Shape>> shapes;
shapes.push_back(std::make_unique<Circle>(5.0));
shapes.push_back(std::make_unique<Rectangle>(4.0, 6.0));
shapes.push_back(std::make_unique<Triangle>(3.0, 4.0, 5.0));
std::cout << "\n--- 透過 Shape* 呼叫虛擬函式 ---\n";
double totalArea = 0.0;
for (const auto& s : shapes) {
s->draw(); // 執行期多型
std::cout << " 面積 = " << s->area()
<< ", 周長 = " << s->perimeter() << "\n";
totalArea += s->area();
}
std::cout << "\n 所有圖形總面積 = " << totalArea << "\n";
std::cout << "\n--- unique_ptr 離開作用域,觀察虛擬解構子 ---\n";
}
std::cout << "\n========================================\n";
std::cout << " 2. 虛擬解構子的重要性\n";
std::cout << "========================================\n";
{
std::cout << "\n--- 無虛擬解構子 ---\n";
BaseNoVirtual* p1 = new DerivedNoVirtual();
delete p1; // 只呼叫 BaseNoVirtual 解構子!衍生類別解構子被跳過
std::cout << "\n--- 有虛擬解構子 ---\n";
BaseVirtual* p2 = new DerivedVirtual();
delete p2; // 正確呼叫 DerivedVirtual → BaseVirtual
}
std::cout << "\n========================================\n";
std::cout << " 3. vtable 觀念驗證\n";
std::cout << "========================================\n";
{
Circle c(3.0);
Rectangle r(2.0, 5.0);
// sizeof 包含 vptr 的大小
std::cout << " sizeof(Shape) = " << sizeof(Shape) << " bytes\n";
std::cout << " sizeof(Circle) = " << sizeof(c) << " bytes\n";
std::cout << " sizeof(Rectangle) = " << sizeof(r) << " bytes\n";
std::cout << " (含有虛擬函式的物件會多一個 vptr)\n";
}
std::cout << "\n========================================\n";
std::cout << " 4. override 關鍵字與樂器多型\n";
std::cout << "========================================\n";
{
std::vector<std::unique_ptr<Instrument>> band;
band.push_back(std::make_unique<Piano>());
band.push_back(std::make_unique<Violin>());
band.push_back(std::make_unique<Piano>());
std::cout << "\n 樂團演奏:\n";
for (const auto& inst : band) {
inst->play(); // 多型:各樂器各自演奏
}
}
std::cout << "\n========================================\n";
std::cout << " 5. 用原始指標示範多型(搭配手動 delete)\n";
std::cout << "========================================\n";
{
Shape* shapes[] = {
new Circle(2.0),
new Rectangle(3.0, 7.0),
new Triangle(5.0, 12.0, 13.0)
};
for (auto* s : shapes) {
s->draw();
std::cout << " 面積 = " << s->area() << "\n";
}
std::cout << "\n--- delete 各物件 ---\n";
for (auto* s : shapes) {
delete s; // 虛擬解構子確保完整解構
}
}
std::cout << "\n========================================\n";
std::cout << " 程式結束\n";
std::cout << "========================================\n";
return 0;
}
Artículos relacionados
C++
c
Actualizado 2026-07-21
deviceAlpha.h
deviceAlpha.h — c source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/deviceAlpha.h).
Leer artículo →
C++
c
Actualizado 2026-07-21
finalproject.c
finalproject.c — c source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/finalproject.c).
Leer artículo →
C++
cpp
Actualizado 2026-07-21
finalproject.cpp
finalproject.cpp — cpp source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/finalproject.cpp).
Leer artículo →
C++
c
Actualizado 2026-07-21
deviceAlpha.h
deviceAlpha.h — c source code from the C++ learning materials (C++/Mavis_Homework/Lab8/deviceAlpha.h).
Leer artículo →
C++
c
Actualizado 2026-07-21
lab8.c
lab8.c — c source code from the C++ learning materials (C++/Mavis_Homework/Lab8/lab8.c).
Leer artículo →
C++
cpp
Actualizado 2026-07-21
lab8.cpp
lab8.cpp — cpp source code from the C++ learning materials (C++/Mavis_Homework/Lab8/lab8.cpp).
Leer artículo →