谈谈C++11中的默认和删除函数(defaulted and deleted functions)及其用途。

参考回答

C++11 引入了默认和删除函数(defaulted and deleted functions),这使得类的设计更加灵活和精确。默认函数允许编译器生成某些成员函数的默认实现,而删除函数则允许显式禁用某些成员函数的生成或调用。这些特性有助于提高代码的安全性、可维护性和明确性。

  • 默认函数(defaulted functions):使用 = default 语法显式请求编译器生成默认实现。
  • 删除函数(deleted functions):使用 = delete 语法显式禁止某些函数的调用。

详细讲解与拓展

1. 默认函数(defaulted functions)

在某些情况下,我们可能希望让编译器自动生成特定的特殊成员函数(如构造函数、拷贝构造函数、赋值操作符等),但也希望显式地指定这些函数,而不是让编译器隐式生成。这时可以使用 = default 来请求编译器生成默认实现。

示例:默认构造函数
#include 

class MyClass {
public:
    MyClass() = default;  // 显式请求默认构造函数
    void printMessage() {
        std::cout << "Hello from MyClass!" << std::endl;
    }
};

int main() {
    MyClass obj;  // 使用默认构造函数
    obj.printMessage();

    return 0;
}
C++

在这个例子中,MyClass 类显式使用 = default 请求编译器生成默认构造函数。这使得类在没有定义任何构造函数时,仍然能够正常工作,并且不需要显式编写构造函数。

示例:默认拷贝构造函数
#include 

class MyClass {
public:
    MyClass() = default;  // 默认构造函数
    MyClass(const MyClass&) = default;  // 默认拷贝构造函数
    void printMessage() const {
        std::cout << "Hello from MyClass!" << std::endl;
    }
};

int main() {
    MyClass obj1;      // 创建对象 obj1
    MyClass obj2 = obj1;  // 使用默认拷贝构造函数

    obj2.printMessage();
    return 0;
}
C++

在这个例子中,MyClass 类显式声明了默认的拷贝构造函数。这样,当我们创建 obj2 时,编译器会使用默认的拷贝构造函数将 obj1 的内容拷贝到 obj2

2. 删除函数(deleted functions)

删除函数通过 = delete 显式禁用某些成员函数的生成或调用。常见的用法是禁止拷贝构造、赋值操作符等,防止不希望的操作。例如,当我们不希望对象被拷贝或赋值时,可以删除相关的函数。

示例:删除拷贝构造函数
#include 

class MyClass {
public:
    MyClass() = default;  // 默认构造函数
    MyClass(const MyClass&) = delete;  // 禁用拷贝构造函数

    void printMessage() const {
        std::cout << "Hello from MyClass!" << std::endl;
    }
};

int main() {
    MyClass obj1;      // 创建对象 obj1
    // MyClass obj2 = obj1;  // 编译错误,拷贝构造函数被删除

    obj1.printMessage();
    return 0;
}
C++

在这个例子中,我们通过 = delete 删除了 MyClass 的拷贝构造函数,因此不能再通过拷贝构造函数创建新对象。如果尝试进行拷贝,会导致编译错误。

示例:删除赋值操作符
#include 

class MyClass {
public:
    MyClass() = default;  // 默认构造函数
    MyClass& operator=(const MyClass&) = delete;  // 禁用赋值操作符

    void printMessage() const {
        std::cout << "Hello from MyClass!" << std::endl;
    }
};

int main() {
    MyClass obj1;      // 创建对象 obj1
    MyClass obj2;      // 创建另一个对象 obj2
    // obj2 = obj1;    // 编译错误,赋值操作符被删除

    obj1.printMessage();
    return 0;
}
C++

在这个例子中,operator= 被删除,因此 obj1obj2 不能进行赋值操作。如果尝试赋值,会导致编译错误。

3. 使用删除函数禁用特定操作

除了拷贝构造和赋值操作符,删除函数还可以用于禁用其他不必要或不安全的操作。例如,禁止移动构造函数或禁止特定类型的函数调用。

示例:禁止移动构造函数
#include 

class MyClass {
public:
    MyClass() = default;  // 默认构造函数
    MyClass(MyClass&&) = delete;  // 禁用移动构造函数

    void printMessage() const {
        std::cout << "Hello from MyClass!" << std::endl;
    }
};

int main() {
    MyClass obj1;      // 创建对象 obj1
    // MyClass obj2 = std::move(obj1);  // 编译错误,移动构造函数被删除

    obj1.printMessage();
    return 0;
}
C++

在这个例子中,我们删除了移动构造函数,这防止了通过 std::move 对象的移动操作,从而避免了可能的不安全操作。

4. 默认和删除函数的实际应用

  • 禁止拷贝:当一个类的对象不应被拷贝时,可以删除拷贝构造函数和赋值操作符。例如,std::unique_ptr 类就禁止了拷贝操作,只允许移动操作。
  • 显式指定构造行为:使用默认构造函数和默认拷贝构造函数,开发者可以显式要求编译器生成相应的函数,而不是依赖于编译器的默认行为。
  • 强制类型安全:删除不必要的操作,如移动构造、拷贝构造,可以避免潜在的错误,增强代码的安全性。

总结

C++11 中的默认和删除函数(= default= delete)是控制类成员函数行为的重要工具。通过使用 = default,我们可以显式请求编译器生成默认实现的特殊成员函数;通过使用 = delete,我们可以显式禁止某些不希望的操作(如拷贝、赋值或移动操作)。这些特性使得类的设计更加灵活、安全,帮助开发者更好地控制对象的生命周期和行为。

发表评论

后才能评论