HOME ABOUT CONTACT

1. C/C++ 修飾詞top

1.1 static

用途:
static 修飾詞根據修飾對象的不同位置,具有多種作用:

1.2 const

用途:
const 表示被修飾的對象不可修改,常見應用:

1.3 virtual

用途:
virtual 用於支援多型(Polymorphism),允許子類別覆寫父類別的方法。被 virtual 修飾的成員函式在執行時根據物件的實際型別決定呼叫的版本,而非編譯時的宣告型別。

1.4 final

用途:
final 用於防止類別或虛函式被進一步的子類覆寫。

1.5 explicit

用途:
explicit 用於防止構造函式的隱式型別轉換,提高代碼的明確性和安全性。


class MyClass {
public:
    explicit MyClass(int x) { }
};

// MyClass obj = 5;  // 編譯錯誤,不允許隱式轉換
MyClass obj(5);      // 正確,顯式呼叫建構式
                        

1.6 mutable

用途:
mutable 允許在 const 成員函式中修改被標記的成員變數,通常用於快取或計數器等不影響物件邏輯狀態的欄位。


class MyClass {
private:
    mutable int cache;
public:
    void getData() const {
        cache = computeValue();  // 即使是 const 函式,仍可修改 cache
    }
};
                        

1.7 noexcept

用途:
noexcept 指定函式不會拋出例外(exceptions),幫助編譯器最佳化,並在違反承諾時直接終止程式。


void safeFunc() noexcept {
    // 保證此函式不會拋出例外
}

void mayThrow() noexcept(false) {  // 預設行為,可能拋出例外
    // ...
}
                        

1.8 [[nodiscard]]

用途:
[[nodiscard]] 是 C++17 引入的屬性,用於提醒開發者不應忽略該函式的回傳值。若呼叫者未使用回傳值,編譯器會發出警告。


[[nodiscard]] int getValue() {
    return 42;
}

int main() {
    getValue();  // 編譯器警告:回傳值未被使用
    int x = getValue();  // 正確
    return 0;
}
                        

2. C/C++ STD 相關top

2.1 std::unique_ptr<T>

概念:
獨佔指標,表示某一時刻只有一個人擁有被指向的物件,而不跟別人共享生命週期。當 unique_ptr 被銷毀時,會自動刪除所指向的物件。無法複製,但可轉移所有權。


std::unique_ptr<int> ptr1(new int(10));
// std::unique_ptr<int> ptr2 = ptr1;  // 錯誤,unique_ptr 不可複製
std::unique_ptr<int> ptr2 = std::move(ptr1);  // 正確,轉移所有權
// 此時 ptr1 為 nullptr,ptr2 擁有該 int 物件
                        

2.2 std::shared_ptr<T>

概念:
共享指標,多個人可以指向同一物件,透過參考計數管理,常用於多執行緒架構。當最後一個 shared_ptr 被銷毀或重設時,被指向的物件才被刪除。


std::shared_ptr<int> ptr1(new int(10));
std::shared_ptr<int> ptr2 = ptr1;  // 參考計數增加至 2
{
    std::shared_ptr<int> ptr3 = ptr1;  // 參考計數增加至 3
}  // ptr3 超出作用域,參考計數減回 2
// ptr1 和 ptr2 都仍有效
                        

2.3 std::weak_ptr<T>

概念:
弱指標,用於打破 shared_ptr 的循環參考問題。weak_ptr 不增加參考計數,但可轉換為 shared_ptr 以臨時使用。


std::shared_ptr<int> shared(new int(10));
std::weak_ptr<int> weak = shared;  // 不增加參考計數

if (auto temp = weak.lock()) {  // lock() 嘗試取得 shared_ptr
    std::cout << *temp << std::endl;
} else {
    std::cout << "物件已被刪除" << std::endl;
}
                        

2.4 std::reference_wrapper<T>

概念:
參考包裝器,用於在需要可複製、可賦值的情況下儲存參考。常用於容器(如 vector)無法直接儲存參考時 (包含抽象類別)。


int x = 10, y = 20;
std::vector<std::reference_wrapper<int>> refs;
refs.push_back(std::ref(x));
refs.push_back(std::ref(y));

for (auto& ref : refs) {
    ref.get() += 5;  // 透過 get() 取得參考並修改原始值
}
// 此時 x = 15, y = 25
                        

3. 應用語意top

3.1 namespace 不給名字(匿名空間)的作用

概念:
匿名命名空間(無名稱的 namespace)內的符號只在當前編譯單位(translation unit)內可見,等同於使用 static 修飾符的舊方式。提供更現代的方式來隱藏符號。


// file.cpp
namespace {
    int helperValue = 0;  // 只在此檔案內可見
    void helperFunc() { }  // 只在此檔案內可見
}

void publicFunc() {
    helperFunc();  // 可以調用
}

// 其他檔案無法存取 helperValue 或 helperFunc
                        

3.2 using 與 typedef 的差異

概念:
兩者都用於型別別名,但語法和功能有所不同:


// typedef 方式
typedef std::vector<int> IntVector;
typedef int (*FuncPtr)(int, int);  // 函式指標,語法較難理解

// using 方式
using IntVector = std::vector<int>;
using FuncPtr = int(*)(int, int);  // 更清晰

// using 獨有:樣板別名
template<typename T>
using Vec = std::vector<T>;
Vec<int> v;  // 簡化使用

// typedef 無法做樣板別名
                        

3.3 建構式列表初始化 vs. 直接初始化的差異

概念:
C++11 引入的初始化列表(Initializer List)相比傳統初始化更安全且功能更強:


// 直接初始化
int x(3.14);           // 允許,x = 3(隱式轉換)
int y = 3.14;          // 允許,y = 3(隱式轉換)

// 列表初始化
int z{3.14};           // 編譯錯誤!禁止窄化轉換
int w{3};              // 正確,無需轉換

// 初始化列表可用於容器和複雜型別
std::vector<int> v1{1, 2, 3};
std::vector<int> v2;
v2 = {4, 5, 6};

// 使用預設值
struct Point {
    int x{0}, y{0};  // 預設值初始化
};
Point p1;              // x = 0, y = 0
Point p2{1, 2};        // x = 1, y = 2
                        

3.4 建構式初始化列表 vs. 建構式體內賦值的差異

概念:
建構式中初始化成員變數有兩種方式,但性能與行為上有重要差異:


class MyClass {
private:
    std::string m_str;
    int m_value;

public:
    // 方式1:使用初始化列表(推薦)
    MyClass(const std::string& str, int val) : m_str(str), m_value(val) {
        // 此時 m_str 和 m_value 已初始化
    }

    // 方式2:在建構式體內賦值(較不高效)
    MyClass(const std::string& str, int val) {
        m_str = str;      // 先呼叫 string 預設建構式,再賦值
        m_value = val;
    }
};

// 性能比較
MyClass obj1("test", 10);  // 初始化列表:1次建構 + 初始化
MyClass obj2("test", 10);  // 體內賦值:1次建構 + 1次複製賦值(多一次操作)
                        

關鍵差異:


class SpecialClass {
private:
    const int m_const;        // const 成員
    int& m_ref;               // 參考成員

public:
    // 只能用初始化列表
    SpecialClass(int c, int& r) : m_const(c), m_ref(r) { }

    // 這個無法編譯
    // SpecialClass(int c, int& r) {
    //     m_const = c;       // 錯誤!const 成員無法賦值
    //     m_ref = r;         // 錯誤!參考無法重新綁定
    // }
};
                        

Last updated: