- C 和 C++ 共通的部分提到前面,各自的部分則放到各自的段落。
- 維護 C++ 中文版面。
- 盡可能只紀錄語言層面知識。
-
-
- Call by value: C 只有此種方法。
In call-by-value, the argument expression is evaluated, and the resulting value is bound to the corresponding variable in the function (frequently by copying the value into a new memory region).
- Call by reference: C++ 另外支援此種方法。C 可以用傳遞指針 (仍為 call by value,value 為位址) 模擬 call by reference 的效果。
In call-by-reference evaluation (also referred to as pass-by-reference), a function receives an implicit reference to a variable used as argument, rather than a copy of its value.
C++
常見問題
- Integer to hex string in C++
#include <iomanip> #include <sstream> #include <string> template< typename T > std::string int_to_hex( T i ) { std::stringstream stream; stream << "0x" << std::uppercase << std::setfill ('0') << std::setw(sizeof(T)*2) << std::hex << i; return stream.str(); }
-
- How do I erase elements from STL containers?
for (auto it = c.begin(); it != c.end(); /* "it" updated inside loop body */ ) { if ( erasing_condition(*it) ) { // Erase the element matching the specified condition // from the associative container. it = c.erase(it); // Note: // erase() returns an iterator to the element // that follows the last element removed, // so we can continue the "for" loop iteration from that position. } else { // Current element does _not_ satisfy erasing condition, // so we can just move on to the next element. ++it; } }
C++0x 概觀
-
- 相對於 GLIBC 所使用的 symbol versioning 機制,針對函式庫提供語言層級的版本控制。
基礎
- Ch1-2: Programming and "Hello, World!"
- Ch3: Objects, Types, and Values
- 在內存中擺放資料的空間稱為物件 (object),物件有其型別 (type),內存有值 (value)。有名字 (name) 的物件稱之為變數 (variable),可透過其名提取該變數的值。
陣列
- C++ Multi-dimensional Arrays
int main () { // an array with 5 rows and 2 columns. int a[5][2] = { {0,0}, {1,2}, {2,4}, {3,6},{4,8}}; // output each array element's value for ( int i = 0; i < 5; i++ ) for ( int j = 0; j < 2; j++ ) { cout << "a[" << i << "][" << j << "]: "; cout << a[i][j]<< endl; } return 0; }
指針
int array[5] = {1, 2, 3, 4, 5}; int *ptr; ptr = array; *(ptr + 1) = 7; *(array + 1) = 7; // 不可做指針運算。
char *names[MAX] = { "Zara Ali", "Hina Ali", "Nuha Ali", "Sara Ali", };
int *foo() { static int i; int i; // 不可。此為堆疊上的位址,隨時間變化。 return &i; }
參考
- C++ References
int i; int &r = i; // 必須要有初值,無法像指針一樣可以有空指針。 void swap(int& a, int& b); int& foo() { static int i; return i; }
類別
- private: 該變數或函式只能在類別自身內部,或是有用 friend 修飾的外部函式內使用。
- protected: 同上。該變數或函式另外能被子類別使用。
- public: 在本類別物件可見範圍內皆可使用。
- Overload
- 同名函式,不同參數個數或是型別。返回型別不同無法重載函式。
class Base { void foo(int); void foo(double); }; void bar(int); void bar(double);
- Override
- 類別繼承時會出現的用語。
class Base { // 要做到動態多型,宣告成 virtual。 void foo(int); }; class Derive : public Base { void foo(int) { /* do different thing */ } };
- name hiding
class Base { public: virtual void foo(double i) { cout << "Base::foo(double) " << endl; } }; class Derive : public Base { public: // Base::foo 被 Derive:foo 給隱藏。 // using Base::foo; void foo(complex<double>) { cout << "Derive::foo(complex<double>) " << endl; } }; int main() { Derive d; d.foo(1l); // Derive::foo(complex<double>) Base* pd = new Derive; pd->foo(1); // Overload 根據靜態型別進行決議。Base::foo(double) }
多型
基類別內要定義虛擬函式。用指針或是參考引用虛擬函式。只能用基類指針指向衍生類物件,反之不可。
class Base { public: virtual ~Base() {} virtual void foo(int i = 10) { cout << "Base::foo(int)" << i << endl; } }; class Derive : public Base { public: void foo(int i = 20) { cout << "Derive::foo(int)" << i << endl; } }; int main() { Base* pd = new Derive; pd->foo(); // Derive::foo(int) 10 delete pd; // Base 必須要有 virtual dtor。 }
- 抽象類別 (abstract class)
- 類別內只要有一個純虛擬函式,便是抽象類別。
- 無法創建抽象類別之物件。
- 相對於 abstract class 即為 concrete class。
class Shape { public: // 其中定義有一個純虛擬函式,留待子類別實作。 virtual void draw() = 0; };
- 執行時期型別資訊
- 用 typeid 來取得指標或參考所實際代表的物件,進而存取其原生類別特定的變數和函式。
容器與迭代
std::list<int> ilist = {1, 2, 3}; for (auto iter = ilist.begin(); iter != ilist.end(); ++iter) std::cout << *iter << " ";
自訂 IO
struct Entr { string name; int number ; }; ostream& operator<<(ostream& os, const Entry& e) { return os << "{\"" << e.name << "\", " << e.number << "\"}"; }
例外處理
int main() { try { std::cout << vec.at(3); } catch (std::out_of_range& err) { std::cout << "out of range!\n"; } }
實用組件
- 資源管理 (Resource Management): memory, lock, socket, thread handle and file handle
- 使用 ctor/dtor 自動取得和釋放資源。RAII (Resource Acquisition Is Initialization)
- Smart pointer
#include <memory> int main() { std::unique_ptr<int> p1(new int(5)); std::unique_ptr<int> p2 = p1; // p1 獨占該指針所有權,無法轉移。 std::cout << *p1; /* 不需要手動 delete */ // delete p1; }
- Regular Expressions
模板
template <typename T> inline T const& Max (T const& a, T const& b) { return a < b ? b:a; }
template <class T> class Stack { private: vector<T> elems; // elements public: void push(T const&); // push element void pop(); // pop element T top() const; // return top element bool empty() const{ // return true if empty. return elems.empty(); } }; template <class T> void Stack<T>::push (T const& elem) { // append copy of passed element elems.push_back(elem); }
模板元編程
相較於傳統編程,元編程 (metaprgramming) 是在編譯時期,由編譯器進行計算。
#include <iostream> // 主模板 (primary template) template < unsigned n > struct factorial { // 遞歸實例化模板 factorial<n-1>,並取得 value 成員當作其值。 // factorial<n-1>::value 可以看做呼叫函數 factorial(n-1) 並取得返回值 value。 static const unsigned value = n * factorial<n-1>::value; }; // 顯式特化模板 (explicit specialization),用來定義終止條件。 template <> struct factorial<0> { static const unsigned value = 1; }; int main() { // 編譯器在遞歸實例化模板 factorial 的過程中會求得 n! 的值。 std::cout << factorial<6>::value << std::endl; // 6! = 720 }
可被編譯器操縱的值稱為元數據 (meta data),常見的元數據為類型 (type) 和整數常量。為了達到靜態多型,通常會將輸入參數和返回值包裝成類型。如此一來,元函數 f 也可被包裝成類 (元函數類),再當作參數傳遞給元函數 g。元函數 g 被稱為高階元函數 (high-order function),意指元函數 g 可以操縱另一元函數 f。元函數可用來計算數值或是類型,數值會被包裝成類型,至於類型計算通常是用來判別某一類型是否具有某種特性,比如該類型是否為一整數 (int) 或是浮點數 (float)。
元函數是一個內含可被公開訪問的 type 成員的類或是樣板類。
template <class T1, class T2> struct apply { typedef int type; }
元函數類是一個內含可被公開訪問的 apply 元函數的類。
struct plus_f { template <class T1, class T2> struct apply { typedef int type; } }
成員名 type 或是 apply 均是約定名稱。如此一來,使用者使用不同的元函數(元函數類)可以直接取用 type (apply)。 元函數轉發 (meta function forwarding) 使得子類可透過公開繼承父類,進而將父類的 type 成員暴露出來。
struct foo : apply {}
數值會被包裝成類型,稱之為整型外覆器 (interal wrapper)。
// int a = int_wrapper<1>::value; template <int x> struct int_wrapper { static int const value = x; };
元數據不可變 (immutable) 且元函數沒有副作用。利用模板進行元編程,需要知道何謂模板顯式特化和部分特化。
進階
反彙編
透過反彙編可以更清楚背後運作的機制。
- libcpp
- libstdc\+\+-v3
文章
術語
-
-
- Combining C’s volatile and const Keywords
// Constant Addresses of Hardware Registers // p_led_reg 是一個 constant 指針,指向一個 volatile uint8_t。 uint8_t volatile * const p_led_reg = (uint8_t *) 0x00080000; // Read-Only Shared-Memory Buffer int const volatile comm_flag; uint8_t const volatile comm_buffer[BUFFER_SIZE]; // Read-Only Hardware Register uint8_t const volatile * const p_latch_reg = (uint8_t *) 0x10000000;