C++中的 =default和=delete

本文深入探讨了C++11中引入的默认函数和删除函数特性。介绍了如何使用'default'关键字为特殊成员函数生成默认实现,以及使用'delete'关键字禁用不需要的函数,提高代码效率和安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先,什么是默认功能呢(Defaulted Function)
明确默认的函数声明式一种新的函数声明方式,在C++11发布时做出了更新。C++11允许添加“=default”说明符到函数声明的末尾,以将该函数声明为显示默认构造函数。这就使得编译器为显示默认函数生成了默认实现,它比手动编程函数更加有效。

例如,每当我们声明一个有参构造函数时,编译器就不会创建默认构造函数。在这种情况下,我们可以使用default说明符来创建默认说明符。以下代码演示了如何创建:

// use of defaulted functions
#include <iostream>
using namespace std;

class A {
public:
    // A user-defined
    A(int x){
        cout << "This is a parameterized constructor";
    }

    // Using the default specifier to instruct
    // the compiler to create the default implementation of the constructor.
    A() = default;
};

int main(){
    A a;          //call A()
    A x(1);       //call A(int x)
    cout<<endl;
    return 0;
} 

在这里插入图片描述
在上面的例子中,我们不必指定构造函数A()的主体,因为通过附加说明符’= default’,编译器将创建此函数的默认实现。

那么使用此“=default”符号有什么限制?

  • 默认函数需要用于特殊的成员函数(默认构造函数,复制构造函数,析构函数等),或者没有默认参数。例如,以下代码解释了非特殊成员函数不能默认:
// non-special member functions can't be defaulted(非特殊成员函数不能使用default) 
class B { 
public: 
    // Error, func is not a special member function. 
    int func() = default;  
      
    // Error, constructor B(int, int) is not a special member function. 
    B(int, int) = default;  
  
    // Error, constructor B(int=0) has a default argument. 
    B(int = 0) = default;  
}; 
int main() { 
    return 0; 
} 

运行结果:
在这里插入图片描述
当我们可以使用“{}”简单的空的实体时,使用’= default’有什么优点?

尽管两者可能表现相同,但使用default而不是使用{}仍然有一定的好处。以下几点做了一定的解释:

  1. 给用户定义的构造函数,即使它什么也不做,使得类型不是聚合,也不是微不足道的。如果您希望您的类是聚合类型或普通类型(或通过传递性,POD类型),那么需要使用’= default’。
  2. 使用’= default’也可以与复制构造函数和析构函数一起使用。例如,空拷贝构造函数与默认拷贝构造函数(将执行其成员的复制副本)不同。对每个特殊成员函数统一使用’= default’语法使代码更容易阅读。

再来说一下Deleted Function

在C ++ 11之前,操作符delete 只有一个目的,即释放已动态分配的内存。而C ++ 11标准引入了此操作符的另一种用法,即:禁用成员函数的使用。这是通过附加= delete来完成的; 说明符到该函数声明的结尾。

使用’= delete’说明符禁用其使用的任何成员函数称为expicitly deleted函数。

虽然不限于它们,但这通常是针对隐式函数。以下示例展示了此功能派上用场的一些任务:

禁用拷贝构造函数:

// copy-constructor using delete operator 
#include <iostream> 
using namespace std; 
  
class A { 
public: 
    A(int x): m(x) { } 
      
    // Delete the copy constructor 
    A(const A&) = delete;      
    // Delete the copy assignment operator 
    A& operator=(const A&) = delete;  
    int m; 
}; 
  
int main() { 
    A a1(1), a2(2), a3(3); 
    // Error, the usage of the copy assignment operator is disabled 
    a1 = a2;   
    // Error, the usage of the copy constructor is disabled 
    a3 = A(a2);  
    return 0; 
} 

禁用不需要的参数转换

// type conversion using delete operator 
#include <iostream> 
using namespace std; 
class A { 
public: 
    A(int) {} 

    // Declare the conversion constructor as a  deleted function. Without this step,  
    // even though A(double) isn't defined,  the A(int) would accept any double value
    //  for it's argumentand convert it to an int 
    A(double) = delete;  
}; 
int main() { 
    A A1(1); 
    // Error, conversion from  double to class A is disabled. 
    A A2(100.1);  
    return 0; 
} 

请注意,删除的函数是隐式内联的,这一点非常重要。删除的函数定义必须是函数的第一个声明。换句话说,以下方法是将函数声明为已删除的正确方法:

class C {
public:
         C(C& a) = delete;
};

但是以下尝试声明删除函数的方法会产生错误:

// incorrect syntax of declaring a member function as deleted 
class C  { 
public: 
    C(); 
}; 
  
// Error, the deleted definition of function C must be the first declaration of the function. 
C::C() = delete;  

最后,明确删除函数有什么好处?
删除特殊成员函数提供了一种更简洁的方法来防止编译器生成我们不想要的特殊成员函数。(如“禁用拷贝构造函数”示例中所示)。
删除正常成员函数或非成员函数可防止有问题的类型导致调用非预期函数(如“禁用不需要的参数转换”示例中所示)。

### C++ 中 `= delete` 的用法及常见场景 #### 一、`= delete` 基本概念 在 C++11 及之后的标准中,`= delete` 是一种显式禁用特定函数的方式。通过这种方式,程序员能够阻止某些操作被调用或隐式生成[^1]。 当某个函数被声明为 `= delete` 后,任何尝试调用该函数的行为都会导致编译期错误。这种机制主要用于防止不希望的操作发生,或者强制用户以某种特定方式使用类的功能[^2]。 --- #### 二、`= delete` 的典型应用场景 ##### 1. **禁用拷贝构造函数赋值运算符** 对于不可复制的对象(如单例模式中的对象),可以通过将拷贝构造函数赋值运算符标记为 `= delete` 来禁止这些行为: ```cpp class NonCopyable { public: NonCopyable() = default; NonCopyable(const NonCopyable&) = delete; // 禁用拷贝构造函数 NonCopyable& operator=(const NonCopyable&) = delete; // 禁用赋值运算符 }; ``` 这样做的目的是确保对象不会意外地被复制或赋值[^3]。 ##### 2. **避免虚函数的删除** 需要注意的是,`= delete` 不适用于虚函数。如果试图对虚函数应用 `= delete`,则会导致编译失败。 ##### 3. **限制模板特化** 在模板编程中,有时需要排除某些类型的实例化。此时可以利用 `= delete` 达到这一目的: ```cpp template<typename T> void process(T t) {} // 显式禁用 int 类型的实例化 template<> void process<int>(int t) = delete; int main() { process(42); // 编译错误:process(int) 被删除 process(3.14f); // 正常工作 } ``` 上述代码展示了如何针对特定类型禁用模板函数。 ##### 4. **避免参数形式转换** 即使一个函数未定义具体实现并标注为 `= delete`,它仍然可以在重载解析阶段参与匹配过程。这使得我们可以利用其来捕获潜在的形式转换问题: ```cpp class MyClass { public: void func(double d); void func(float f) = delete; // 删除 float 版本 }; MyClass obj; obj.func(0.5); // OK, 使用 double 参数版本 obj.func(0.5f); // 错误:float 参数版本已被删除 ``` 在这里,`func(float)` 被明确移除,从而避免了可能由浮点数精度损失引发的问题。 --- #### 三、总结 `= delete` 提供了一种简洁而高效的方法来约束类接口的设计,增强了程序的安全性可维护性。合理运用它可以有效减少不必要的副作用以及难以追踪的运行时错误。 ---
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一倾而尽

你的鼓励将是我最大的动力,谢谢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值