天天看點

C++構造函數的default和delete

轉自: https://blog.csdn.net/u010591680/article/details/71101737

C++11中,當類中含有不能預設初始化的成員變量時,可以禁止預設構造函數的生成,

myClass()=delete;//表示删除預設構造函數

myClass()=default;//表示預設存在構造函數

當類中含有不能預設拷貝成員變量時,可以禁止預設構造函數的生成,

myClass(const myClass&)=delete;//表示删除預設拷貝構造函數,即不能進行預設拷貝

myClass & operatir=(const myClass&)=delete;//表示删除預設拷貝構造函數,即不能進行預設拷貝

——————————————————————————————————————————————————————

https://blog.csdn.net/u012333003/article/details/25299939 同時C++規定,一旦程式員實作了這些函數的自定義版本,則編譯器不會再自動生産預設版本。注意隻是不自動生成預設版本,當然還是可手動生成預設版本的。當我們自己定義了待參數的構造函數時,我們最好是聲明不帶參數的版本以完成無參的變量初始化,此時編譯是不會再自動提供預設的無參版本了。我們可以通過使用關鍵字default來控制預設構造函數的生成,顯式地訓示編譯器生成該函數的預設版本。比如:

class MyClass
{
  public:
    MyClass()=default;  //同時提供預設版本和帶參版本,類型是POD的
    MyClass(int i):data(i){}
  private:
    int data;
};           

有些時候我們希望限制預設函數的生成。典型的是禁止使用拷貝構造函數,以往的做法是将拷貝構造函數聲明為private的并不提供實作,這樣當拷貝構造對象時編譯不能通過,C++11則使用delete關鍵字顯式訓示編譯器不生成函數的預設版本。比如:

class MyClass
{
  public:
     MyClass()=default;
     MyClass(const MyClass& )=delete;
  ......
}           

當然,一旦函數被delete過了,那麼重載該函數也是非法的,該函數我們習慣上稱為删除函數。

二、default和delete的其他用途

  上面我們已經看到在類中我們可用default和delete修飾成員函數,使之成為預設函數或者删除函數,在類的外面,也可以在類定義之外修飾成員函數,比如:

class MyClass
{
  public:
    MyClass()=default;
    MyClass() &operator=(const MyClass& );
);
//在類的定義外用default來指明預設函數版本
inline MyClass& MyClass::operator=(const MyClass& )=default;
           

而關于delete的顯式删除,并非局限于成員函數,由此我們也知default是隻局限作用于類的部分成員函數的。于是我們還可用delete來避免不必要的隐式資料類型轉換。比如:

class MyClass
{
  public:
    MyClass(int i){};
    MyClsss(char c)=delete;  //删除char版本的構造函數
};
void Fun(MyClass m){}
int main()
{
  Func(3);
  Func('a');  //編譯不能通過
  MyClass m1(3);
  MyClass m2('a');  //編譯不能通過
}
           

這是因為char版本的構造函數被删除後,試圖從char構造MyClass對象的方式是不允許的了。但去掉這句的函數删除後,編譯器會隐式的将a轉換為整型使得編譯通過,調用的是整型構造函數,這可能并不是你所想要的。但是如果這樣:

class MyClass
{
  public:
    MyClass(int i){};
    explicit MyClsss(char c)=delete;  //删除explicit的char版本的構造函數
};
void Fun(MyClass m){}
int main()
{
  Func(3);
  Func('a');  //編譯可通過
  MyClass m1(3);
  MyClass m2('a');  //編譯不能通過
}
           

将構造函數explicit後,構造函數一樣的還是不能發生char的構造,因為char構造版本被删除了,但在Func的調用用,編譯器會嘗試将c轉換為int,即Func(\\a')會調用一次MyClass(int )構造,順利通過編譯。于是我們不提倡explicit和delete混用。

對與普通函數delete也有類型的效果。比如:

void Func(int i){};
void Func(char c)=delete;  //顯式删除char版本
int main()
{
  Func(3);
  Func('c);  //無法編譯通過
  return 0;
}           

這裡因為Func的char版本已經被删除,故Func('c')會編譯失敗。

delete的有趣的用法還有删除operator new操作符,編碼在堆上配置設定該類的對象如:

void* operator new(std::size_t)=delete;           

另外析構函數也是可以delete的

這樣做的目的是我們在指定記憶體位置進行記憶體配置設定時并不需要析構函數來完成對象級别的清理,這時我們可顯示删除析構函數來限制自定義類型在棧上或者靜态的構造。

繼續閱讀