浅析 explicit 关键字

浅析 explicit 关键字

文章目录

  • 浅析 explicit 关键字
    • 前言
    • 案例剖析
    • 补充案例
    • 总结

前言

​ C++ 提供了多种方式来实现类型转换和构造对象,然而,有时候这些方式会导致一些意想不到的结果,比如隐式转换复制初始化。为了避免这些潜在的问题,C++ 引入了 explicit 关键字,它可以限制一些不必要或不安全的转换和初始化。在本文中,我们将介绍 explicit 关键字的作用和用法,以及它如何提高代码的可读性和安全性。


案例剖析

​ 为了说明 explicit 关键字的作用和用法,我们首先定义两个结构体 A 和 B,它们都有一个接受 int 参数的构造函数和一个返回 bool 值的转换函数,但是 B 的构造函数和转换函数都被 explicit 修饰了,而 A 的没有。

struct A 
{A(int) {}operator bool() const { return true; }
};struct B 
{explicit B(int) {}explicit operator bool() const { return true; }
};

接下来,我们定义两个函数 doA 和 doB,它们分别接受 A 和 B 类型的参数。

void doA(A a) {}void doB(B b) {}

然后,我们在 main 函数中创建一些 A 和 B 类型的对象,并尝试用不同的方式进行初始化和转换。

int main() {A a1(1);     // OK:直接初始化A a2 = 1;    // OK:复制初始化A a3{1};     // OK:直接列表初始化A a4 = {1};  // OK:复制列表初始化A a5 = (A)1; // OK:允许 static_cast 的显式转换doA(1);      // OK:允许从 int 到 A 的隐式转换if (a1); // OK:使用转换函数 A::operator bool() 的从 A 到 bool 的隐式转换bool a6(a1); // OK:使用转换函数 A::operator bool() 的从 A 到 bool 的隐式转换bool a7 = a1; // OK:使用转换函数 A::operator bool() 的从 A 到 bool 的隐式转换bool a8 = static_cast<bool>(a1); // OK :static_cast 进行直接初始化B b1(1);     // OK:直接初始化//    B b2 = 1;        // 错误:被 explicit//    修饰构造函数的对象不可以复制初始化B b3{1};     // OK:直接列表初始化//    B b4 = { 1 };        // 错误:被 explicit//    修饰构造函数的对象不可以复制列表初始化B b5 = (B)1; // OK:允许 static_cast 的显式转换//    doB(1);            // 错误:被 explicit//    修饰构造函数的对象不可以从 int 到 B 的隐式转换if (b1); // OK:被 explicit 修饰转换函数 B::operator bool() 的对象可以从 B 到 bool// 的按语境转换bool b6(b1); // OK:被 explicit 修饰转换函数 B::operator bool() 的对象可以从 B// 到 bool 的按语境转换//    bool b7 = b1;        // 错误:被 explicit 修饰转换函数//    B::operator bool() 的对象不可以隐式转换bool b8 = static_cast<bool>(b1); // OK:static_cast 进行直接初始化return 0;
}

从上面的代码中,我们可以看出以下几点:

  • explicit 修饰的构造函数只能用于直接初始化直接列表初始化不能用于复制初始化和复制列表初始化这样可以避免一些不必要的类型转换,比如将一个 int 值赋给一个 B 类型的变量,或者将一个花括号列表赋给一个 B 类型的变量。
  • explicit 修饰的转换函数只能用于显式转换和按语境转换,不能用于隐式转换。这样可以避免一些不安全的类型转换,比如将一个 B 类型的对象赋给一个 bool 类型的变量,或者将一个 B 类型的对象作为条件表达式。按语境转换是指在某些特定的语境中,编译器会自动调用 explicit 修饰的转换函数,比如 if 语句,while 语句,for 语句,switch 语句,逻辑运算符,条件运算符,static_cast,和 bool 构造函数。
  • explicit 关键字可以提高代码的清晰度和一致性,避免一些潜在的错误和歧义。

补充案例

上面案例中A、B构造函数都属于单参数类型,下面印证仅有多参数构造函数的类是否存在同样的结论。此处以“分数”为例构建结构体案例:

例如,我们可以定义一个表示分数的结构体 Fraction,它有一个接受两个 int 参数的构造函数,表示分子和分母,以及一个返回 double 值的转换函数,表示分数的小数值。

我们可以用 explicit 关键字来修饰这两个函数,以防止一些不合理或不明确的转换和初始化

struct Fraction 
{int num; // 分子int den; // 分母// explicit 修饰的构造函数,防止从 int 或 int,int 到 Fraction 的隐式转换和复制初始化explicit Fraction(int n, int d = 1) : num(n), den(d) {}// explicit 修饰的转换函数,防止从 Fraction 到 double 的隐式转换explicit operator double() const { return static_cast<double>(num) / den; }
};

接着创建一些 Fraction 类型的对象,并尝试用不同的方式进行初始化和转换。

Fraction f1(1, 2); // OK:直接初始化
//		Fraction f2 = 1;        // 错误:被 explicit 修饰的构造函数不可以复制初始化
//		Fraction f3 = 1, 2;     // 错误:被 explicit 修饰的构造函数不可以复制初始化
Fraction f4{ 1, 2 }; // OK:直接列表初始化
//		Fraction f5 = { 1, 2 };	// 错误:被 explicit 修饰的构造函数不可以复制列表初始化
Fraction f6 = (Fraction)1;	// OK:允许 static_cast 的显式转换
Fraction f7 = static_cast<Fraction>(1); // OK:static_cast 进行直接初始化//		double d1 = f1; // 错误:被 explicit 修饰的转换函数不可以隐式转换
double d2(f1);  // OK:被 explicit 修饰的转换函数可以按语境转换
double d3 = static_cast<double>(f1); // OK:static_cast 进行直接初始化

我们看到上面 f6、f7 对象通过类型强转生成 Fraction 对象这个过程属于显式转换,所以经过强转生成的临时对象可以成功执行拷贝构造和赋值运算函数将值传给 f6、f7 对象。

  • explicit 修饰的构造函数可以防止从 int 或 int,int 到 Fraction 的隐式转换和复制初始化。例如,如果我们想要创建一个表示 1/2 的分数,我们应该使用 Fraction f(1, 2) 或 Fraction f{1, 2},而不是 Fraction f = 1 或 Fraction f = {1, 2},因为后者会创建一个表示 1/1 或 2/1 的分数,这显然不是我们的目的。
  • explicit 修饰的转换函数可以防止从 Fraction 到 double 的隐式转换。例如,如果我们想要计算一个分数的倒数,我们应该使用 static_cast<double>(f)来显式地将分数转换为 double 类型,然后再进行除法运算,而不是直接使用 1 / f,因为后者会先将 1 隐式地转换为 Fraction 类型,然后再调用 Fraction 类的重载的除法运算符,这可能会得到一个错误的结果。

总结

  • explicit 修饰构造函数时,可以防止隐式转换和复制初始化
  • explicit 修饰转换函数时,可以防止隐式转换,但按语境转换除外

​ 在本文中介绍了 explicit 关键字的作用和用法,以及它如何提高代码的可读性和安全性。我们了解了 explicit 关键字可以用于修饰构造函数和转换函数,以阻止隐式转换和复制初始化,也了解了 explicit 修饰的构造函数和转换函数的使用场景和限制。我们认识到 explicit 关键字可以帮助我们避免一些不必要或不安全的类型转换,提高代码的清晰度和一致性。希望本文对你有所帮助,如果你有任何问题或建议,欢迎在评论区留言。谢谢!

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/506058.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【兔子机器人】根据自身机器人参数修改simulink模型

关节电机 机体初始高度 &#xff01;&#xff01;&#xff01;接下来尝试修改各腿的坐标朝向

黑马JavaWeb开发跟学(三)Web前端开发Vue-Element

黑马JavaWeb开发跟学三.Web前端开发Vue-Element 1 Ajax1.1 Ajax介绍1.1.1 Ajax概述1.1.2 Ajax作用1.1.3 同步异步 1.2 原生Ajax1.3 Axios1.3.1 Axios的基本使用1.3.2 Axios快速入门1.3.3 请求方法的别名1.3.4 案例 2 前后台分离开发2.1 前后台分离开发介绍2.2 YAPI2.2.1 YAPI介…

解决Java并发问题的常见思路

写在文章开头 近期对一些比较老的项目进行代码走查&#xff0c;碰到一些极端的并发编程恶习&#xff0c;所以笔者就基于此文演示这类问题以及面对并发编程时我们应该需要了解一些常见套路。 Hi&#xff0c;我是sharkChili&#xff0c;是个不断在硬核技术上作死的java coder&am…

实战:Oracle Weblogic 11g 安装部署(10.3.6.0)

导读 本文介绍在redhat linux 6.6上安装Oracle weblogic 11g&#xff08;10.3.6.0&#xff09;版本 环境&#xff1a;redhat6.6 jdk 1.7 1、下载webLogic10.3.6 http://www.oracle.com/technetwork/cn/middleware/weblogic/downloads/wls-main-091116-zhs.html2 、在linux的ro…

数的范围 刷题笔记

思路 寻找第一个大于等于目标的 数 因为该数组是升序的 所以 我们可以采用二分的方式 逼近答案 定义一个左指针和一个右指针 当左右指针重合时 就是我们要找的答案 当我们寻找第一个大于等于x的数时 a[mid]>x,答案在mid处 或者在mid的左边 因此让rmid继续逼近 如果…

python:pyecharts 画基金净值 月K线图

pip install pyecharts1.9.1 pyecharts-1.9.1-py3-none-any.whl 我想在本地&#xff08;PC) 画出 基金净值 月K线图&#xff0c;不想每次看图都需联网。 cd my_dir mkdir echarts cd echarts curl -O https://assets.pyecharts.org/assets/echarts.min.js 修改一下开源代码 …

记录一次架构优化处理性能从3千->3万

0.背景 优化Kafka消费入Es&#xff0c;适配600台设备上报数据&#xff0c;吞吐量到达2万每秒 1.环境配置 2.压测工具 3.未优化之前的消费逻辑 4.优化之后的消费流程 5.多线程多ESclient 6.修改ES配置&#xff0c;增加kafka分区&#xff0c;增加线程&#xff0c;提升吞吐量 7.…

【数据结构】实现队列

大家好&#xff0c;我是苏貝&#xff0c;本篇博客带大家了解队列&#xff0c;如果你觉得我写的还不错的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 目录 一. 队列的概念及结构二. 队列的实现队列的结构体初始化销毁队尾插入队头删除显示第一个节点的值…

【双指针】移动零

移动零 链接 . - 力扣&#xff08;LeetCode&#xff09;. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/move-zeroes/submissions/506832592/ 题目 题解 异地变…

RFID(Radio Frequency Identification)技术笔记

一、RFID的介绍 RFID&#xff0c;全称为Radio Frequency Identification&#xff0c;即射频识别技术&#xff0c;也常被称为电子标签或无线射频识别。它是一种非接触式的自动识别技术&#xff0c;通过射频信号自动识别目标对象并获取相关数据&#xff0c;识别过程无需人工干预&…

Redis、Elasticsearch(ES)、RocketMQ和MYSql 持久化对比

在现代大数据和分布式系统中&#xff0c;数据持久化是一个至关重要的话题。本文将针对 Redis、Elasticsearch&#xff08;ES&#xff09;、 RocketMQ和MYSql 这四种常见的数据存储和消息队列系统进行持久化方面的对比分析&#xff0c;帮助读者更好地了解它们各自的特点和适用场…

【Mybatis】多表映射 第二期

文章目录 一、多表映射概念二、对一映射三、对多映射四、多表映射总结4.1 多表映射优化4.2 多表映射总结 一、多表映射概念 多表关系&#xff1a; 一对一一对多 | 多对一多对多 一个 客户 对应 多个订单一个订单 对应 一个客户 举例&#xff1a; 对一 实体类设计&#xff1a…