2010年8月20日 星期五

Class Default Constructor

假設有個類別T


class T
{
};
main()
{
  T tObj;
  T *tObj = new T;
  T tObj = T();
}


不管怎麼宣告一個物件,都會去 call 該類別的建構式,有時我們沒寫建構式,用的就是 C++ 預設的建構式,包括無參數的建構式 T::T(),另外一個常常被乎略的就是 copy constructor 為 T::T(const &T)

copy constructor 也是預設會自動產生的,所以你才有辦法這麼做


T tObj;
tObj.m_ID = 1;
T tNewObj = T(tObj);


預設的 copy constructor 會幫你把兩個物件內的各成員一個一個用 = 相接,這就叫無腦複製,竟然如此,這時後要特別注意類別內是否有指標成員,例如


class T
{
  int m_nID;
  TCHAR *m_strName;
  ~T()
  {
    if(m_strName)
    {
      free(m_strName);
      m_strName = NULL;
    }
  }
};

T *tObj = new T;
tObj->m_strName = "Ascii";
T tNewObj = T(*tObj);
delete tObj;

之後如果你使用 tNewObj.m_strName 將會發生無可預期的錯誤,因為 tObj 與 tNewObj 的 m_strName 是同一個,但 tObj 已經解構了,m_strName 已經被指向 NULL 了,而 0 是不可取用的位址。

所以當你的類別有指標成員變數,請記得自己寫 copy constructor 以此為例


T::T(const T &refT)
{
  this->m_nID = refT.m_nID;
  this->m_strName = (TCHAR*)malloc(sizeof(TCHAR) * (lstrlen(refT.m_strName) + 1));
  // 記憶體空間 + 1 是因為這個成員是字串,需要結束字元 \0
  _tcscpy(this->m_strName , refT.m_strName);
}


若會用到 = 來相等兩個物件,也要記得覆寫 =


T& operator=(const T &refT)
{
  this->m_nID = refT.m_nID;
  this->m_strName = (TCHAR*)malloc(sizeof(TCHAR) * (lstrlen(refT.m_strName) + 1));
  _tcscpy(this->m_strName , refT.m_strName);
  return *this;
}


除此之外需注意的,不只建構式會預設自動產生,有些 function 也是會預設產生的,例如
operator= // 指定運算子
operator& // 取址運算子

沒有留言:

張貼留言