📜  C++ 11中的显式默认和删除函数

📅  最后修改于: 2021-05-30 14:44:53             🧑  作者: Mango

默认函数

什么是默认函数?
显式默认的函数声明是C++ 11标准中引入的一种新形式的函数声明,它允许您添加‘= default;’。符到一个函数声明的端部来声明函数作为明确默认函数。这使编译器为显式默认函数生成默认实现,这比手动编程的函数实现更有效。

例如,无论何时我们声明参数化的构造函数,编译器都不会创建默认的构造函数。在这种情况下,我们可以使用默认说明符来创建默认说明符。以下代码演示了如何:

// C++ code to demonstrate the
// use of defaulted functions
#include 
using namespace std;
  
class A {
public:
  
    // A user-defined 
    // parameterized constructor
    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()
{
    // executes using defaulted constructor
    A a; 
      
    // uses parametrized constructor
    A x(1); 
    return 0;
}

输出

This is a parameterized constructor

在上述情况下,我们不必指定构造函数A()的主体,因为通过附加说明符’= default’,编译器将创建此函数的默认实现。

使函数默认设置有哪些约束?
默认函数必须是特殊的成员函数(默认构造函数,复制构造函数,析构函数等),或者没有默认参数。例如,以下代码说明了不能默认使用非特殊成员函数的情况:

// C++ code to demonstrate that 
// non-special member functions 
// can't be defaulted
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; 
};
  
// driver program
int main()
{
    return 0;
}

当我们可以简单地使用'{}’保留函数的空白时,’= default’有什么优势?
即使两者的行为相同,但使用default仍比将构造函数的主体保留为空更有好处。以下几点说明了如何:

  1. 提供一个用户定义的构造函数,即使它什么也不做,会使该类型不是聚合的,并且也不是琐碎的。如果您希望您的类是集合类型或琐碎类型(或通过传递性,则是POD类型),则需要使用“ = default”。
  2. 使用’= default’也可以与复制构造函数和析构函数一起使用。例如,空副本构造函数将与默认副本构造函数(它将执行其成员的成员级复制)不同。对这些特殊成员函数中的每一个统一使用’= default’语法,使代码更易于阅读。
删除函数

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

任何通过使用’= delete’说明符禁用其用法的成员函数都称为显式删除函数。

尽管不限于它们,但是通常对隐式函数执行此操作。以下示例展示了一些可以使用此功能的任务:

禁用复制构造函数

// C++ program to disable the usage of
// copy-constructor using delete operator
#include 
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;
}

禁用不希望的参数转换

// C++ program to disable undesirable argument
// type conversion using delete operator
#include 
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;
};

但是,以下尝试声明已删除函数将产生错误:

// Sample C++ code to demonstrate the 
// 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; 

显式删除功能的优点是什么?

  1. 删除特殊成员函数提供了一种更清洁的方法,可以防止编译器生成我们不想要的特殊成员函数。 (如“禁用复制构造函数”示例中所示)。
  2. 删除普通成员函数或非成员函数可防止出现问题的类型提升导致调用意外函数(如“禁用不希望的参数转换”示例中所示)。
要从最佳影片策划和实践问题去学习,检查了C++基础课程为基础,以先进的C++和C++ STL课程基础加上STL。要完成从学习语言到DS Algo等的更多准备工作,请参阅“完整面试准备课程”