1. 程式人生 > >C++建構函式的default和delete

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的

這樣做的目的是我們在指定記憶體位置進行記憶體分配時並不需要解構函式來完成物件級別的清理,這時我們可顯示刪除解構函式來限制自定義型別在棧上或者靜態的構造。