如以前提到的,在沒有聲明默認特殊成員函數的時候,編譯器會自動幫咱們補充,但有時候咱們並不但願存在這些函數,好比:咱們不但願某個類經過拷貝的方式實例化一個新的對象。就算咱們不定義拷貝構造函數和重載拷貝賦值運算符,編譯器也會爲咱們自動完成。c++
#include <bits/stdc++.h> using namespace std; class LiF { public: LiF() = default; LiF(int _lif) { lif = _lif; } void print(){cout << lif << endl;} ~LiF() = default; private: int lif; }; int main() { LiF* lif1 = new LiF{2}; LiF lif2 = *lif1; // 咱們不但願這個類能夠拷貝構造 lif2.print(); delete lif1; lif1 = nullptr; return 0; }
寫出如上代碼以後,編譯能夠經過,但違反了咱們的初衷。函數
再看下面這個場景:spa
double add(double x, double y) { return x + y; } int main() { int a, b; add(a, b); return 0; }
這裏咱們聲明瞭double
類型的add
函數,編譯能夠經過。假設此時咱們不但願其餘類型能經過隱式轉換調用這個函數,那這裏就須要禁用掉會發生轉換的版本。code
由此C++11引入了delete
關鍵字,用於顯式禁用某些函數。對象
與default
不一樣的是,delete
沒有限制函數必須是類的特殊成員函數。作用域
#include <bits/stdc++.h> using namespace std; class LiF { public: LiF() = default; LiF(int _lif) { lif = _lif; } LiF(const LiF& l) = delete; // 顯式禁用拷貝構造函數 LiF& operator= (const LiF& l) = delete; // 顯式禁用拷貝賦值運算符 void print(){cout << lif << endl;} ~LiF() = default; private: int lif; }; int main() { LiF* lif1 = new LiF{2}; LiF lif2 = *lif1; // 這裏將引起報錯,由於拷貝賦值運算符已被顯式禁用 lif2.print(); delete lif1; lif1 = nullptr; return 0; }
double add(double x, double y) { return x + y; } int add(int, int) = delete; // 顯式禁用add函數的int版本 int main() { int a, b; add(a, b); // 這裏將引起報錯,由於對應的函數已被顯式禁用 return 0; }
這裏有一點須要注意的是,delete
關鍵字僅僅禁用了函數的調用,但在編譯過程當中,名字查找和重載解析時,該函數名還是一個有效的標識符。編譯器
分析第二個例子:咱們聲明並定義了double
類型的add
函數,聲明並顯式禁用了add
函數的int
重載。在編譯到add(a, b)
時,編譯器進行名字查找,找到全局做用域的add
函數定義,並經過精確匹配最終定位到int add(int, int)
這個重載上,隨後編譯器發現這是一個deleted(已被禁用)函數,引起報錯。it