2010年9月7日 星期二

不允許隱轉型的 explicit 關鍵字

假設我們定義一個國小學生的類別用於管理各項資料


class CEleStudent
{
private:
  int m_nYears;
  TCHAR *m_tcName;
public:
  CEleStudent() {m_nYears = 7; m_tcName = _T("NoName");};
  CEleStudent(int n, const TCHAR *tc)
  {
    m_nYears = n;
    m_tcName = (TCHAR*)malloc(sizeof(TCHAR) * (lstrlen(tc) + 1));
    _tcscpy(m_tcName , tc);
  };
  CEleStudent(int n) {m_nYears = n; m_tcName = NULL;};
};


在我們沒有明確定義 operator= 的時後,若我做撰寫以下程式碼會發生一些問題


int main()
{
  CEleStudent std;
  std = 9;
  cout << std.m_tcName; return TRUE;
}


在宣告std時因為沒有指定任何建構式,所以經過預設無參數的建構式後產生了年紀7歲的物件,但下一行 std = 9 就有問題了,編譯器會將此行代碼拆解成它自己看得懂的方式,


CEleStudent tmp(10); // m_nYears 為 10,m_tcName 為 NULL
std = tmp; // 將 Years 由 7 改為 10,NoName 改為 NULL 空指標


這種轉換過程就稱為隱轉型,在有適當參數的建構式下編譯器會自行呼叫,就像 int n = 9; double dbl; dbl = n; 這是最常見的隱轉型。

在 m_tcName 為空指標的狀況下,第三行的 cout 就有可能在執行期間出問題嘍,加上原本被 malloc 分派出來的記憶體沒有經過 free() 的動作也是一個問題,畢免這種情況的發生可以使用 explicit 關鍵字,就像它的名稱一樣,該類別的建構式無法被調用來做隱式轉型的動作,
修改如下


class CEleStudent
{
  ...
  explicit CEleStudent(int n) {m_nYears = n; m_tcName = NULL;};
};


如此當有其他人使用你的類別時,只要出現 obj = 整數這種指令,編譯期即會收到一項無法轉型的 compil error 的訊息,必須明確的指明


CEleStudent std;
std = (std)9;

std = std(9);


這可以確實的將一些錯誤擋在編譯時期,比發生在執行期好多了,但需注意的是 explicit 關鍵字用於多參數的建構式是會產生語法錯誤的,所以 CEleStudent(int n, const TCHAR *tc) 就沒辦法加上 explicit。

沒有留言:

張貼留言