谈谈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;
}
在这个例子中,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;
}
在这个例子中,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;
}
在这个例子中,我们通过 = 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;
}
在这个例子中,operator= 被删除,因此 obj1 和 obj2 不能进行赋值操作。如果尝试赋值,会导致编译错误。
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;
}
在这个例子中,我们删除了移动构造函数,这防止了通过 std::move 对象的移动操作,从而避免了可能的不安全操作。
4. 默认和删除函数的实际应用
- 禁止拷贝:当一个类的对象不应被拷贝时,可以删除拷贝构造函数和赋值操作符。例如,
std::unique_ptr类就禁止了拷贝操作,只允许移动操作。 - 显式指定构造行为:使用默认构造函数和默认拷贝构造函数,开发者可以显式要求编译器生成相应的函数,而不是依赖于编译器的默认行为。
- 强制类型安全:删除不必要的操作,如移动构造、拷贝构造,可以避免潜在的错误,增强代码的安全性。
总结
C++11 中的默认和删除函数(= default 和 = delete)是控制类成员函数行为的重要工具。通过使用 = default,我们可以显式请求编译器生成默认实现的特殊成员函数;通过使用 = delete,我们可以显式禁止某些不希望的操作(如拷贝、赋值或移动操作)。这些特性使得类的设计更加灵活、安全,帮助开发者更好地控制对象的生命周期和行为。