1. C/C++ 修飾詞
1.1 static
1.2 const
1.3 virtual
1.4 final
1.5 explicit
1.6 mutable
1.7 noexcept
1.8 [[nodiscard]]
2. C/C++ STD 相關
2.1 std::unique_ptr<T>
2.2 std::shared_ptr<T>
2.3 std::weak_ptr<T>
2.4 std::reference_wrapper<T>
3. 應用語意
3.1 匿名命名空間
3.2 using 與 typedef
3.3 列表初始化 vs 直接初始化
3.4 初始化列表 vs 賦值
用途:
static 修飾詞根據修飾對象的不同位置,具有多種作用:
用途:
const 表示被修飾的對象不可修改,常見應用:
用途:
virtual 用於支援多型(Polymorphism),允許子類別覆寫父類別的方法。被 virtual 修飾的成員函式在執行時根據物件的實際型別決定呼叫的版本,而非編譯時的宣告型別。
用途:
final 用於防止類別或虛函式被進一步的子類覆寫。
用途:
explicit 用於防止構造函式的隱式型別轉換,提高代碼的明確性和安全性。
class MyClass {
public:
explicit MyClass(int x) { }
};
// MyClass obj = 5; // 編譯錯誤,不允許隱式轉換
MyClass obj(5); // 正確,顯式呼叫建構式
用途:
mutable 允許在 const 成員函式中修改被標記的成員變數,通常用於快取或計數器等不影響物件邏輯狀態的欄位。
class MyClass {
private:
mutable int cache;
public:
void getData() const {
cache = computeValue(); // 即使是 const 函式,仍可修改 cache
}
};
用途:
noexcept 指定函式不會拋出例外(exceptions),幫助編譯器最佳化,並在違反承諾時直接終止程式。
void safeFunc() noexcept {
// 保證此函式不會拋出例外
}
void mayThrow() noexcept(false) { // 預設行為,可能拋出例外
// ...
}
用途:
[[nodiscard]] 是 C++17 引入的屬性,用於提醒開發者不應忽略該函式的回傳值。若呼叫者未使用回傳值,編譯器會發出警告。
[[nodiscard]] int getValue() {
return 42;
}
int main() {
getValue(); // 編譯器警告:回傳值未被使用
int x = getValue(); // 正確
return 0;
}
概念:
獨佔指標,表示某一時刻只有一個人擁有被指向的物件,而不跟別人共享生命週期。當 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 物件
概念:
共享指標,多個人可以指向同一物件,透過參考計數管理,常用於多執行緒架構。當最後一個 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 都仍有效
概念:
弱指標,用於打破 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;
}
概念:
參考包裝器,用於在需要可複製、可賦值的情況下儲存參考。常用於容器(如 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
概念:
匿名命名空間(無名稱的 namespace)內的符號只在當前編譯單位(translation unit)內可見,等同於使用 static 修飾符的舊方式。提供更現代的方式來隱藏符號。
// file.cpp
namespace {
int helperValue = 0; // 只在此檔案內可見
void helperFunc() { } // 只在此檔案內可見
}
void publicFunc() {
helperFunc(); // 可以調用
}
// 其他檔案無法存取 helperValue 或 helperFunc
概念:
兩者都用於型別別名,但語法和功能有所不同:
// 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 無法做樣板別名
概念:
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
概念:
建構式中初始化成員變數有兩種方式,但性能與行為上有重要差異:
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: