• 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 概觀

基礎

  1. Ch1-2: Programming and "Hello, World!"
  2. 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
  • 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;
      };

容器與迭代

Data Structure

  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) 且元函數沒有副作用。利用模板進行元編程,需要知道何謂模板顯式特化和部分特化。

進階

反彙編

文章

術語

優化術語

參考書籍

登录