当前位置: 首页 > article >正文

default、delete 和 explicit

在 C++11 中,增加了几个新的关键字和特性,它们用来更精确地控制类的基本函数(如构造函数、拷贝构造函数、赋值运算符等)。其中,defaultdeleteexplicit 都是用于这些基本函数的关键字,目的是让程序员在特定的情况下更加灵活地控制类的行为。

1. default:默认函数

概念

default 关键字用于告诉编译器自动生成某个函数的默认实现。可以用来显式地声明编译器默认的构造函数、拷贝构造函数、赋值运算符和析构函数等。

在某些情况下,如果你没有显式地定义某些基本函数(如构造函数、拷贝构造函数等),编译器会自动生成它们。但是,有时你可能需要明确指定某些函数应该由编译器自动生成,而不是手动实现。default 关键字就是为此设计的。

用法
  • 默认构造函数:如果你没有显式定义构造函数,编译器会自动生成一个默认构造函数。如果你希望显式地声明一个默认构造函数,可以使用 default
  • 拷贝构造函数、赋值运算符:如果你没有定义这些函数,编译器会自动生成它们。如果你不想使用编译器生成的实现,可以手动删除它们;如果你希望使用默认实现,可以显式地使用 default
示例
class MyClass {
public:
    MyClass() = default;  // 显式指定使用编译器自动生成的默认构造函数
    MyClass(const MyClass&) = default;  // 显式指定使用编译器自动生成的拷贝构造函数
    MyClass& operator=(const MyClass&) = default;  // 显式指定使用编译器自动生成的赋值运算符
    ~MyClass() = default;  // 显式指定使用编译器自动生成的析构函数
};

int main() {
    MyClass obj1;  // 使用默认构造函数
    MyClass obj2 = obj1;  // 使用默认的拷贝构造函数
    obj1 = obj2;  // 使用默认的赋值运算符
}
理解
  • 如果没有 default,编译器会根据需要自动生成这些函数。但是,当你想显式控制某些函数的行为时,可以使用 default。比如,某些类型的成员变量可能需要特定的初始化,或者拷贝操作需要特定的处理。
  • 使用 default 可以避免编写冗余的代码,也让程序员明确表达出他们希望让编译器自动生成这些函数。

2. delete:删除函数

概念

delete 关键字用于显式地告诉编译器某个函数是不可用的,也就是禁止调用某个函数。常用于禁止拷贝构造函数、赋值运算符等不希望被调用的函数。通常是为了防止对象的拷贝或赋值,或阻止某些操作。

用法
  • 禁止拷贝构造函数或赋值运算符:可以使用 delete 来禁止编译器自动生成拷贝构造函数或赋值运算符。这在有些场景中是必需的,比如实现单例模式时,防止对象被复制。
示例
class NoCopy {
public:
    NoCopy() = default;
    
    // 禁止拷贝构造函数和赋值运算符
    NoCopy(const NoCopy&) = delete;
    NoCopy& operator=(const NoCopy&) = delete;
};

int main() {
    NoCopy obj1;
    // NoCopy obj2 = obj1;  // 编译错误:拷贝构造函数被删除
    // obj1 = obj2;  // 编译错误:赋值运算符被删除
}
理解
  • NoCopy 类中,我们使用 delete 来显式地禁止了拷贝构造函数和赋值运算符。这使得 NoCopy 类型的对象不能被复制或赋值。这是常见的场景,比如 单例模式 或者 资源管理 类(例如 std::unique_ptr)中,用来确保对象的唯一性和防止意外复制。
  • delete 使得编译器直接报错,而不只是生成一个空实现,避免了不小心使用了被禁用的函数。

3. explicit:显式构造函数

概念

explicit 关键字用于修饰构造函数,防止它在不明确的情况下进行隐式类型转换。没有 explicit 的构造函数可以用来进行隐式类型转换,而带有 explicit 的构造函数不能用于隐式转换。它是用来避免不希望的隐式类型转换或“魔法”行为。

用法
  • 防止隐式类型转换:如果你有一个构造函数,并且不希望它在某些情况下被自动调用(例如进行隐式类型转换),可以使用 explicit 来禁止隐式转换。
示例
class MyClass {
public:
    explicit MyClass(int x) { // 显式构造函数
        std::cout << "MyClass constructed with " << x << std::endl;
    }
};

int main() {
    MyClass obj1(10);  // 正常:直接传递参数
    // MyClass obj2 = 10;  // 编译错误:没有隐式构造函数
}
理解
  • 在没有 explicit 的情况下,MyClass(10) 可以隐式地用作 MyClass 对象的构造,例如 MyClass obj = 10; 这样的代码会尝试隐式地用 10 来构造一个 MyClass 对象。
  • 使用 explicit 后,构造函数就不能进行隐式类型转换了。这样,如果你试图将 10 隐式地转换为 MyClass 对象,编译器会报错。这有助于避免因隐式转换导致的意外行为或错误。
场景
  • 防止隐式转换:在某些情况下,允许编译器进行隐式类型转换可能会导致不希望的结果,使用 explicit 可以避免这种情况。
  • 增加代码的可读性和安全性:当你希望构造函数只通过显式调用来创建对象时,使用 explicit 可以确保构造函数不被自动调用。

总结

  • default:显式请求编译器生成某个函数的默认实现。用在构造函数、拷贝构造函数、赋值运算符、析构函数等地方,用来避免手动编写一些常见的函数实现。
  • delete:显式禁止某个函数的使用,如拷贝构造函数、赋值运算符等,用于防止某些操作(如拷贝、赋值)在某些情况下被执行。
  • explicit:防止构造函数进行隐式类型转换,要求构造函数必须显式地调用。避免不期望的隐式转换导致程序错误。

通过正确地使用这三个关键字,可以在 C++11 中编写更加安全、清晰且易于维护的代码,避免不必要的自动化行为和复杂的隐式转换。


http://www.kler.cn/a/456149.html

相关文章:

  • Spark生态圈
  • 在FreeBSD或Ubuntu平台仿真RISCV64位版本FreeBSD系统相关技术文档
  • 基于Spring Boot + Vue3实现的在线商品竞拍管理系统源码+文档
  • 记录命令行操作树莓派Wifi的方式
  • FAISS进行高效的向量检索 原理详解
  • MyBatis中XML文件的模板
  • Vite系列课程 | 11. Vite 配置文件中 CSS 配置(Modules 模块化篇)
  • xadmin后台首页增加一个导入数据按钮
  • CA系统的设计(CA证书生成,吊销,数字签名生成)
  • 关于Qt::BlockingQueuedConnection的死锁问题
  • Fastbot-iOS(iOS monkey)schema参数的指定方式
  • 【工具变量】地级市减碳重视程度及减碳词频数据(2003-2024年)
  • Mybatis-Plus updateById 方法更新无效及空值处理
  • 【C++面向对象——类与对象】Computer类(头歌实践教学平台习题)【合集】
  • mprpc框架代码详解
  • 【HarmonyOS之旅】ArkTS语法(二)->动态构建UI元素
  • Spring Boot介绍、入门案例、环境准备、POM文件解读
  • UE(虚幻)学习(一) UE5.3.2和VS2022的安装以及遇到的问题和一些CS8604、CA2017报错问题.
  • HIVE数据仓库分层
  • 华为麦芒5(安卓6)termux记录 使用ddns-go,alist