S SmartDocs
Chuỗi bài: C++ cpp 265 dòng · Cập nhật 2026-04-03

class_basics.cpp

C++/Part2_物件導向/Ch08_類別與物件/class_basics.cpp

// ============================================================
// Ch08 — 類別基礎、this 指標、const 成員函式
// 編譯:g++ -std=c++17 -Wall -o class_basics class_basics.cpp
// ============================================================

#include <iostream>
#include <string>
#include <iomanip>

// ============================================================
// 1. BankAccount — 基本類別示範
//    展示:成員變數、成員函式、getter/setter、const 方法
// ============================================================

class BankAccount {
private:
    std::string owner;
    double balance;

public:
    // 建構子 — 以成員初始化列表初始化
    BankAccount(const std::string& owner, double initialBalance)
        : owner(owner), balance(initialBalance > 0 ? initialBalance : 0.0) {}

    // 存款
    bool deposit(double amount) {
        if (amount <= 0) {
            std::cout << "    ✗ 存款金額必須大於 0" << std::endl;
            return false;
        }
        balance += amount;
        std::cout << "    ✓ 存入 " << amount << " 元" << std::endl;
        return true;
    }

    // 取款
    bool withdraw(double amount) {
        if (amount <= 0) {
            std::cout << "    ✗ 取款金額必須大於 0" << std::endl;
            return false;
        }
        if (amount > balance) {
            std::cout << "    ✗ 餘額不足(餘額: " << balance
                      << ", 欲取: " << amount << ")" << std::endl;
            return false;
        }
        balance -= amount;
        std::cout << "    ✓ 取出 " << amount << " 元" << std::endl;
        return true;
    }

    // const 成員函式 — 不修改物件狀態
    double getBalance() const { return balance; }
    const std::string& getOwner() const { return owner; }

    void printInfo() const {
        std::cout << "    帳戶持有人: " << owner
                  << ", 餘額: " << std::fixed << std::setprecision(2)
                  << balance << " 元" << std::endl;
    }
};

// ============================================================
// 2. Vector2D — this 指標與鏈式呼叫
// ============================================================

class Vector2D {
private:
    double x;
    double y;

public:
    Vector2D(double x = 0.0, double y = 0.0) : x(x), y(y) {}

    // 回傳 *this 以支援鏈式呼叫
    Vector2D& setX(double x) {
        this->x = x;    // this->x 是成員,x 是參數
        return *this;
    }

    Vector2D& setY(double y) {
        this->y = y;
        return *this;
    }

    Vector2D& add(const Vector2D& other) {
        this->x += other.x;
        this->y += other.y;
        return *this;
    }

    Vector2D& scale(double factor) {
        x *= factor;
        y *= factor;
        return *this;
    }

    // const 成員函式
    double getX() const { return x; }
    double getY() const { return y; }

    double magnitude() const {
        return std::sqrt(x * x + y * y);
    }

    void print(const std::string& label = "") const {
        if (!label.empty()) std::cout << "    " << label << " = ";
        else std::cout << "    ";
        std::cout << "(" << x << ", " << y << ")" << std::endl;
    }
};

// ============================================================
// 3. DateInfo — const 成員函式 vs 非 const
// ============================================================

class DateInfo {
private:
    int year;
    int month;
    int day;

public:
    DateInfo(int y, int m, int d) : year(y), month(m), day(d) {}

    // const 成員函式 — 讀取用
    int getYear()  const { return year; }
    int getMonth() const { return month; }
    int getDay()   const { return day; }

    bool isLeapYear() const {
        return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
    }

    std::string toString() const {
        return std::to_string(year) + "/"
             + std::to_string(month) + "/"
             + std::to_string(day);
    }

    // 非 const 成員函式 — 修改用
    void setYear(int y)  { year = y; }
    void setMonth(int m) { month = m; }
    void setDay(int d)   { day = d; }

    void print() const {
        std::cout << "    日期: " << toString()
                  << (isLeapYear() ? "(閏年)" : "(平年)") << std::endl;
    }
};

// ============================================================
// 4. 接受 const 物件的函式
// ============================================================

void printAccountSummary(const BankAccount& account) {
    // 只能呼叫 const 成員函式
    std::cout << "    [摘要] " << account.getOwner()
              << " 的餘額為 " << account.getBalance() << " 元" << std::endl;
}

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

int main() {
    std::cout << "========================================" << std::endl;
    std::cout << " Ch08 類別基礎完整範例" << std::endl;
    std::cout << "========================================\n" << std::endl;

    // ------ 1. BankAccount ------
    std::cout << "【1】BankAccount — 基本類別操作\n" << std::endl;

    BankAccount acc1("小明", 1000.0);
    BankAccount acc2("小華", 500.0);

    acc1.printInfo();
    acc2.printInfo();
    std::cout << std::endl;

    std::cout << "  小明的操作:" << std::endl;
    acc1.deposit(500.0);
    acc1.withdraw(200.0);
    acc1.withdraw(2000.0);  // 餘額不足
    acc1.deposit(-100.0);   // 金額無效
    std::cout << std::endl;

    acc1.printInfo();
    std::cout << std::endl;

    // 使用接受 const 參考的函式
    std::cout << "  帳戶摘要(透過 const& 函式):" << std::endl;
    printAccountSummary(acc1);
    printAccountSummary(acc2);
    std::cout << std::endl;

    // ------ 2. Vector2D — this 指標與鏈式呼叫 ------
    std::cout << "【2】Vector2D — this 指標與鏈式呼叫\n" << std::endl;

    Vector2D v1(3.0, 4.0);
    v1.print("v1");
    std::cout << "    v1 的長度 = " << v1.magnitude() << std::endl;
    std::cout << std::endl;

    // 鏈式呼叫:setX → setY → scale
    Vector2D v2;
    v2.setX(1.0).setY(2.0).scale(3.0);
    v2.print("v2 (鏈式設定)");
    std::cout << std::endl;

    // 鏈式呼叫:add → scale
    Vector2D v3(1.0, 1.0);
    Vector2D v4(2.0, 3.0);
    v3.print("v3");
    v4.print("v4");
    v3.add(v4).scale(2.0);
    v3.print("v3.add(v4).scale(2)");
    std::cout << std::endl;

    // ------ 3. DateInfo — const 成員函式示範 ------
    std::cout << "【3】DateInfo — const 成員函式\n" << std::endl;

    DateInfo d1(2024, 2, 29);
    DateInfo d2(2023, 6, 15);

    d1.print();
    d2.print();
    std::cout << std::endl;

    // const 物件 — 只能呼叫 const 成員函式
    const DateInfo constDate(2000, 1, 1);
    constDate.print();                      // ✓ print() 是 const
    std::cout << "    年份: " << constDate.getYear() << std::endl;  // ✓ getYear() 是 const
    // constDate.setYear(2025);             // ✗ 編譯錯誤!const 物件不可修改
    std::cout << std::endl;

    // 非 const 物件可以呼叫所有方法
    d2.setYear(2028);
    d2.print();
    std::cout << std::endl;

    // ------ 4. 物件陣列 ------
    std::cout << "【4】物件陣列\n" << std::endl;

    BankAccount accounts[] = {
        BankAccount("張三", 10000.0),
        BankAccount("李四", 25000.0),
        BankAccount("王五", 8000.0),
    };

    double totalBalance = 0.0;
    for (const auto& acc : accounts) {
        acc.printInfo();
        totalBalance += acc.getBalance();
    }
    std::cout << "    ─────────────────────────────" << std::endl;
    std::cout << "    總餘額: " << std::fixed << std::setprecision(2)
              << totalBalance << " 元" << std::endl;

    std::cout << "\n========================================" << std::endl;
    std::cout << " 範例結束" << std::endl;
    std::cout << "========================================" << std::endl;

    return 0;
}

Bài viết liên quan