如以前提到的,在没有声明默认特殊成员函数的时候,编译器会自动帮咱们补充,但有时候咱们并不但愿存在这些函数,好比:咱们不但愿某个类经过拷贝的方式实例化一个新的对象。就算咱们不定义拷贝构造函数和重载拷贝赋值运算符,编译器也会为咱们自动完成。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