S SmartDocs
Serie: C++ cpp 286 líneas · Actualizado 2026-04-03

access_control.cpp

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

// ============================================================
// Ch08 — 存取控制、static 成員
// 編譯:g++ -std=c++17 -Wall -o access_control access_control.cpp
// ============================================================

#include <iostream>
#include <string>
#include <vector>
#include <cmath>

// ============================================================
// 1. Student — static 成員變數追蹤物件數量
// ============================================================

class Student {
private:
    std::string name;
    int score;
    static int totalCount;       // 靜態成員變數 — 所有物件共享

public:
    Student(const std::string& name, int score)
        : name(name), score(score) {
        ++totalCount;
        std::cout << "    [建立] " << name
                  << "(目前學生數: " << totalCount << ")" << std::endl;
    }

    ~Student() {
        --totalCount;
        std::cout << "    [銷毀] " << name
                  << "(剩餘學生數: " << totalCount << ")" << std::endl;
    }

    // const 成員函式
    const std::string& getName() const { return name; }
    int getScore() const { return score; }

    void print() const {
        std::cout << "    " << name << ": " << score << " 分" << std::endl;
    }

    // static 成員函式 — 不需物件即可呼叫
    static int getTotalCount() {
        return totalCount;
    }
};

// static 成員變數必須在類別外定義
int Student::totalCount = 0;

// ============================================================
// 2. Circle — 展示封裝與資料驗證
// ============================================================

class Circle {
private:
    double radius;
    static constexpr double PI = 3.14159265358979;
    static int instanceCount;

public:
    explicit Circle(double r = 1.0) : radius(r > 0 ? r : 1.0) {
        ++instanceCount;
    }

    ~Circle() {
        --instanceCount;
    }

    // Getter
    double getRadius() const { return radius; }

    // Setter — 帶驗證
    void setRadius(double r) {
        if (r > 0) {
            radius = r;
        } else {
            std::cout << "    ⚠ 半徑必須大於 0,維持原值 "
                      << radius << std::endl;
        }
    }

    // const 成員函式
    double area() const { return PI * radius * radius; }
    double circumference() const { return 2.0 * PI * radius; }
    double diameter() const { return 2.0 * radius; }

    void print() const {
        std::cout << "    Circle(r=" << radius
                  << ") → 面積=" << area()
                  << ", 周長=" << circumference() << std::endl;
    }

    // static 成員函式
    static int getInstanceCount() { return instanceCount; }
    static double getPI() { return PI; }
};

int Circle::instanceCount = 0;

// ============================================================
// 3. AccessDemo — 展示 public / private / protected
// ============================================================

class AccessDemo {
public:
    int publicVar = 1;
    void publicMethod() const {
        std::cout << "    publicMethod() — 任何地方都能呼叫" << std::endl;
        privateMethod();    // 類別內部可以呼叫 private 方法
    }

protected:
    int protectedVar = 2;
    void protectedMethod() const {
        std::cout << "    protectedMethod() — 類別內部及衍生類別可呼叫" << std::endl;
    }

private:
    int privateVar = 3;
    void privateMethod() const {
        std::cout << "    privateMethod() — 只有類別內部可呼叫"
                  << "(privateVar=" << privateVar << ")" << std::endl;
    }
};

// 衍生類別示範 protected 的可見性
class DerivedDemo : public AccessDemo {
public:
    void test() const {
        std::cout << "    [衍生類別]" << std::endl;
        std::cout << "      publicVar = " << publicVar << std::endl;
        std::cout << "      protectedVar = " << protectedVar << std::endl;
        // std::cout << privateVar;  // 編譯錯誤!private 不可存取

        publicMethod();
        protectedMethod();
        // privateMethod();  // 編譯錯誤!
    }
};

// ============================================================
// 4. Config — static 成員函式實現全域設定
// ============================================================

class Config {
private:
    static std::string appName;
    static int maxConnections;
    static bool debugMode;

public:
    // 禁止建立實例 — 純工具類別
    Config() = delete;

    static void setAppName(const std::string& name) { appName = name; }
    static void setMaxConnections(int max) {
        if (max > 0 && max <= 1000) maxConnections = max;
    }
    static void setDebugMode(bool enabled) { debugMode = enabled; }

    static const std::string& getAppName() { return appName; }
    static int getMaxConnections() { return maxConnections; }
    static bool isDebugMode() { return debugMode; }

    static void printAll() {
        std::cout << "    應用程式名稱: " << appName << std::endl;
        std::cout << "    最大連線數: " << maxConnections << std::endl;
        std::cout << "    除錯模式: " << (debugMode ? "開啟" : "關閉") << std::endl;
    }
};

// static 成員定義
std::string Config::appName = "MyApp";
int Config::maxConnections = 100;
bool Config::debugMode = false;

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

int main() {
    std::cout << "========================================" << std::endl;
    std::cout << " Ch08 存取控制與 static 成員" << std::endl;
    std::cout << "========================================\n" << std::endl;

    // ------ 1. Student — static 計數 ------
    std::cout << "【1】Student — static 成員追蹤物件數量\n" << std::endl;

    std::cout << "  初始學生數: " << Student::getTotalCount() << "\n" << std::endl;

    {
        Student s1("小明", 90);
        Student s2("小華", 85);
        Student s3("小美", 92);

        std::cout << "\n  區塊內學生數: " << Student::getTotalCount() << std::endl;
        std::cout << std::endl;

        s1.print();
        s2.print();
        s3.print();
        std::cout << std::endl;
    }
    // s1, s2, s3 離開作用域,解構子被呼叫

    std::cout << "\n  區塊外學生數: " << Student::getTotalCount() << "\n" << std::endl;

    // ------ 2. Circle — 封裝與驗證 ------
    std::cout << "【2】Circle — 封裝、驗證、static\n" << std::endl;

    Circle c1(5.0);
    Circle c2(3.0);
    Circle c3;           // 使用預設半徑 1.0

    c1.print();
    c2.print();
    c3.print();
    std::cout << std::endl;

    std::cout << "  Circle 實例數: " << Circle::getInstanceCount() << std::endl;
    std::cout << "  PI = " << Circle::getPI() << std::endl;
    std::cout << std::endl;

    // 測試驗證
    std::cout << "  測試 setter 驗證:" << std::endl;
    c3.setRadius(10.0);
    c3.print();
    c3.setRadius(-5.0);  // 無效值
    c3.print();
    std::cout << std::endl;

    // ------ 3. 存取層級 ------
    std::cout << "【3】存取修飾詞示範\n" << std::endl;

    AccessDemo base;
    std::cout << "  [基礎類別 — 外部存取]" << std::endl;
    std::cout << "    publicVar = " << base.publicVar << std::endl;
    base.publicMethod();
    // base.protectedMethod();  // ✗ 外部不可存取 protected
    // base.privateMethod();    // ✗ 外部不可存取 private
    std::cout << std::endl;

    DerivedDemo derived;
    std::cout << "  [衍生類別存取測試]" << std::endl;
    derived.test();
    std::cout << std::endl;

    // ------ 4. Config — 純 static 類別 ------
    std::cout << "【4】Config — 純 static 工具類別\n" << std::endl;

    std::cout << "  預設設定:" << std::endl;
    Config::printAll();
    std::cout << std::endl;

    Config::setAppName("教學系統");
    Config::setMaxConnections(50);
    Config::setDebugMode(true);

    std::cout << "  修改後設定:" << std::endl;
    Config::printAll();
    std::cout << std::endl;

    // ------ 5. 封裝的實際好處 ------
    std::cout << "【5】封裝的好處 — 對比\n" << std::endl;

    std::cout << "  ❌ 沒有封裝(struct 直接存取):" << std::endl;
    std::cout << "    circle.radius = -10;  // 不合法但無法阻止" << std::endl;
    std::cout << std::endl;

    std::cout << "  ✓ 有封裝(class + setter):" << std::endl;
    std::cout << "    circle.setRadius(-10); // setter 會拒絕不合法值" << std::endl;
    std::cout << std::endl;

    std::cout << "  封裝三大好處:" << std::endl;
    std::cout << "    1. 資料驗證 — 確保物件狀態始終合法" << std::endl;
    std::cout << "    2. 隱藏實作 — 外部不依賴內部結構" << std::endl;
    std::cout << "    3. 維護彈性 — 修改內部不影響使用者" << std::endl;

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

    return 0;
}

Artículos relacionados