C++学习(三十七)=delete和=default

本文介绍了如何在C++中使用=delete禁用编译器默认生成的函数,如构造函数、拷贝构造函数等,并通过示例展示了其用法。同时,也探讨了=default关键字,用于要求编译器生成默认函数的场景。

编译器默认为一个类生成的默认函数

  1. 默认构造函数
  2. 默认析构函数
  3. 默认拷贝构造函数
  4. 默认赋值函数
  5. 移动构造函数
  6. 移动拷贝函数

=delete
1. 禁止使用编译器默认生成的函数

假如上面的几个函数中,不想使用其中某个,可以将其定义为private,或者使用=delete。

#include <iostream>
using namespace std;

class DataOnly {
public:
    DataOnly () {}
    ~DataOnly () {}

    DataOnly (const DataOnly & rhs) = delete; //禁止使用该函数
    DataOnly & operator=(const DataOnly & rhs) = delete; //禁止使用该函数

    DataOnly (const DataOnly && rhs) {}
    DataOnly & operator=(DataOnly && rhs) {}
};

int main(int argc, char *argv[]) {
    DataOnly data1;
    DataOnly data2(data1); // error: call to deleted constructor of 'DataOnly'
    DataOnly data3 = data1; // error: call to deleted constructor of 'DataOnly'
    return 0;
}

2. delete 关键字可用于任何函数,不仅仅局限于类的成员函数

#include <iostream>
using namespace std;

class DataOnly {
public:
    void fun(int a) {}
    void fun(float a) = delete;
};

int main(int argc, char *argv[]) {
    DataOnly data1;
    data1.fun(1); // OK
    data1.fun(0.5); // error: call to member function 'fun' is ambiguous
    return 0;
}

3. 模板特化:在模板特例化中,可以用delete来过滤一些特定的形参类型

例如:Widget 类中声明了一个模板函数,当进行模板特化时,要求禁止参数为 void* 的函数调用。
1. 按照私有不实现思路,应该是将特例化的函数声明为私有型,如下:

#include <iostream>
using namespace std;

class Widget {
public:
    template<typename T>
    void ProcessPointer(T* ptr) {
        cout << typeid (T).name() << endl;
    }
private:        
    void ProcessPointer(void*) {
        cout << "void" << endl;
    }
};

int main(int argc, char *argv[]) {
    Widget w;
    int* ip = NULL;
    w.ProcessPointer(ip);

    void* vp = NULL;
    w.ProcessPointer(vp); //error: 'ProcessPointer' is a private member of 'Widget' w.ProcessPointer(vp);
    return 0;

}

    =delete直接添加在后面就可以解决这个问题

= defaule

在程序员重载了自己上面提到的C++编译器默认生成的函数之后,C++编译器将不在生成这些函数的默认形式。
但是C++允许我们使用=default来要求编译器生成一个默认函数,如

struct Point {
    Point()=default;
    Point(int _x, int _y) : x(_x), y(_y) {}
    int x = 0;
    int y = 0;
}

这样相当于无参的构造函数也是可以使用的。

 

 

 

<think>好的,我需要回答用户关于C++=default=delete的用法及区别的问题。首先,我应该回顾一下这两个关键字的基本概念。根据用户提供的引用,=default用于显式要求编译器生成默认的函数实现,而=delete则是禁止编译器生成特定函数,或者禁用非成员函数,防止不期望的类型转换或调用。 接下来,我需要整理它们的应用场景。比如,当用户自定义了有参构造函数后,编译器不再生成默认构造函数,这时可以使用=default来恢复默认构造函数的生成。而对于=delete,常见的情况是禁用拷贝构造函数或拷贝赋值运算符,以防止对象被拷贝,这在管理资源时尤为重要,比如智能指针的实现。 然后,我需要区分两者的使用范围。根据引用[4],=delete可以用于任何函数,包括普通成员函数非成员函数,而=default仅适用于编译器能够自动生成的默认特殊成员函数,如构造函数、析构函数、拷贝控制成员等。例如,用户可能希望禁止某个函数接受某些参数类型,这时可以使用=delete来删除特定的重载版本,避免隐式转换带来的问题。 还需要提到使用这两个关键字的好处。比如,使用=default可以保持代码的简洁,同时明确表达意图,而=delete则增强了代码的安全性,防止误用某些函数。引用[1]中提到,删除正常成员函数或非成员函数可以防止有问题的类型导致调用非预期的函数,比如禁用不需要的参数转换。 此外,需要结合具体的代码示例来说明两者的用法。比如引用[1]中的例子,类A定义了有参构造函数后,使用A() = default来生成默认构造函数。而如果希望禁用拷贝构造函数,可以声明其为=delete,这样编译器不会生成默认的拷贝构造,任何尝试拷贝该类的对象都会导致编译错误。 最后,我应该总结两者的主要区别,包括用途、适用范围语法要求。确保用户能够清晰理解何时使用=default,何时使用=delete,以及它们如何帮助编写更安全、更高效的C++代码。</think>### C++中`=default`与`=delete`的用法及区别 #### 一、`=default`的用途 1. **显式生成默认函数** 当类中已定义其他构造函数(如带参构造函数),但需要保留默认构造函数时,可通过`=default`显式要求编译器生成默认实现。例如: ```cpp class A { public: A(int x) {} // 用户定义构造函数 A() = default; // 显式生成默认构造函数 }; ``` 此操作确保`A a;`能调用默认构造函数[^1]。 2. **适用于特殊成员函数** `=default`仅可用于编译器默认生成的函数,包括: - 默认构造函数 - 拷贝/移动构造函数 - 拷贝/移动赋值运算符 - 析构函数 示例: ```cpp class MyClass { public: MyClass() = default; // 默认构造函数 MyClass(const MyClass&) = default; // 拷贝构造函数 MyClass& operator=(const MyClass&) = default; // 拷贝赋值运算符 }; ``` 通过`=default`,可保持特殊成员函数的默认行为,同时允许其他自定义操作[^2]。 --- #### 二、`=delete`的用途 1. **禁用特殊成员函数** 用于阻止编译器生成默认实现,常见于禁用拷贝或移动操作。例如: ```cpp class NonCopyable { public: NonCopyable() = default; NonCopyable(const NonCopyable&) = delete; // 禁用拷贝构造 NonCopyable& operator=(const NonCopyable&) = delete; // 禁用拷贝赋值 }; ``` 此时尝试拷贝`NonCopyable`对象会引发编译错误,避免资源重复释放等问题[^3]。 2. **禁止特定函数调用** `=delete`还可用于普通成员函数或非成员函数,防止隐式类型转换或参数匹配问题。例如: ```cpp void process(int x) {} void process(double) = delete; // 禁止使用double参数调用 process(10); // 允许 process(3.14); // 编译错误 ``` 此用法可避免因类型转换导致的逻辑错误[^1]。 --- #### 三、关键区别总结 | **特性** | **`=default`** | **`=delete`** | |----------------|-----------------------------------------|-----------------------------------------| | **用途** | 显式生成默认函数实现 | 禁用函数生成或调用 | | **适用范围** | 仅限编译器可生成的默认特殊成员函数 | 任意函数(包括普通成员函数、非成员函数) | | **语法要求** | 需在函数声明末尾添加 | 可在函数声明或定义中使用 | | **典型场景** | 保留默认构造函数或拷贝控制语义 | 禁用拷贝、限制参数类型或特定重载 | --- #### 四、应用示例 1. **`=default`恢复默认行为** 当类需要同时支持自定义构造默认构造时: ```cpp class B { public: B(int value) : data(value) {} B() = default; // 显式生成默认构造函数 private: int data = 0; }; ``` 2. **`=delete`防止隐式转换** 禁用不需要的构造函数重载: ```cpp class String { public: String(const char* str) {} String(char) = delete; // 禁止通过char类型构造 }; String s1("hello"); // 允许 String s2('a'); // 编译错误 ``` --- #### 五、优点总结 - **`=default`**:保持代码简洁,明确依赖编译器生成的默认逻辑,避免手动实现冗余代码[^4]。 - **`=delete`**:增强类型安全性,防止不合理的操作或参数转换,提升代码健壮性[^1]。 相关问题
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值