【C++】explicit关键字详解(explicit关键字是什么? 为什么需要explicit关键字? 如何使用explicit 关键字)

【C++】explicit关键字详解(explicit关键字是什么? 为什么需要explicit关键字? 如何使用explicit 关键字)

目录

一、前言

二、explicit关键字是什么? 

 三、构造函数还具有类型转换的作用

 🍎单参构造函数

✨引出 explicit 关键字 

 🍍多参构造函数

✨为什么需要explicit关键字? 

✨怎么使用explicit关键字?

四、总结 

 五、共勉


一、前言

        在我们自己平时写 C++ 代码的时候,较少会用到 explicit关键字 。但是在C++相关的标准类库中,看到explicit关键字的频率还是很高的。既然出现的频率这么高,那么我们就来看看explicit关键字的作用到底是干什么的。

二、explicit关键字是什么? 

        explicit是C++中的一个关键字,它用来修饰只有一个参数的类构造函数,以表明该构造函数是显式的,而非隐式的。当使用explicit修饰构造函数时,它将禁止类对象之间的隐式转换,以及禁止隐式调用拷贝构造函数。 
       这能这么说,大家不太好理解,既然解释中提到了类的构造函数  那么下面我将从构造函数中详细的给大家,讲解explicit其中的含义。

 三、构造函数还具有类型转换的作用

        在理解 explicit 关键字 之前,我们必须要了解构造函数的类型转换作用,以便于我们更好的理解 explicit 关键字 ,如果有不懂构造函数的老铁,可以来看看这篇文章:构造函数

 🍎单参构造函数

还是来说说老朋友日期类,我们通过下面这个日期类进行讲解
class Date { public: // 构造函数 Date(int year) :_year(year) // 初始化列表 {} private: int _year; int _month = 3; int _day = 31; }; 
  • 对于下面的 d1 很清楚一定是调用了有参构造进行初始化,不过对于 d2 来说,也是一种构造方式
int main() { // d1 和 d2 都会调用构造函数 Date d1(2022); Date d2 = 2023; return 0; } 
  •  我们依旧通过调试来看就会非常清晰,这种 【Date d2 = 2023】 写法也会去调用构造函数
      此时,大家可能会产生疑问,这种构造方式从来没有见过,为什么 【Date d2 = 2023】会调用 构造函数呢?  其实这都是因为有【隐式类型转换】的存在,下面我将从一个简单的例子来为大家讲解。
  • 引用详解,我有提到过【隐式类型转换】这个概念,像下面将一个int类型的数值赋值给到一个double类型的数据,此时就会产生一个隐式类型转换
int i = 1; double d = i; 
  • 对于类型转换而言,这里并不是将值直接赋值给到左边的对象,而是在中间呢会产生一个临时变量,例如右边的这个 i 会先去构造一个临时变量,这个临时变量的类型是 [double] 。把它里面的值初始化为 1,然后再通过这个临时对象进行拷贝构造给d,这就是编译器会做的一件事
  • 那对于这个 d2 其实也是一样,2023会先去构造一个临时对象,这个临时对象的类型是[Date]把它里面的year初始化为2023,然后再通过这个临时对象进行拷贝构造给到d2

 💬小蛋:不是说构造函数有初始化列表吗?拷贝构造怎么去初始化呢?

//拷贝构造 Date(const Date& d) :_year(d._year) ,_month(d._month) ,_day(d._day) {} 
  •   同学,别忘了【拷贝构造】也是属于构造函数的一种哦,也是会有初始化列表的
 刚才说到了中间会产生一个临时对象,而且会调用构造 + 拷贝构造,那此时我们在Date类中写一个拷贝构造函数,调试再去看看会不会去进行调用
  • 很明显没有,我在进入Date类后一直在按F11,但是却进不到拷贝构造中,这是为什么呢?
  •  原因其实在于编译器在这里地方做了一个优化,将【构造 + 拷贝构造】优化成了【一个构造】,因为编译器在这里觉得构造再加拷贝构造太费事了,干脆就合二为一了。其实对于这里的优化不同编译器是有区别的,像一下VC++、DevC++可能就不会去优化,越是新的编译器越可能去进行这种优化。在本文的最后一个模块我还会详细展开分析

💬小蛋:但您是怎么知道中间赋值这一块产生了临时对象呢?如果不清楚编译器的优化机制这一块肯定就会认为这里只有一个构造 

  • 这点确实是,若是我现在不是直接赋值了,而是去做一个引用,此时会发生什么呢?
Date& d3 = 2024; 
  • 可以看到,报出了一个错误,原因就在于d3是一个Date类型,2024则是一个内置类型的数据
  • 但若是我在前面加一个const做修饰后,就不会出现问题了,这是为什么呢?
  • 其实这里的真正原因就在于产生的这个【临时变量】(临时变量具有常性),它就是通过Date类的构造函数构造出来的,同类型之间可以做引用。还有一点就是临时变量具有常性,所以给到一个const类型修饰对象不会有问题 

引出 explicit 关键字 

        但若是你不想让这种隐式类型转换发生怎么办呢?此时就可以使用到C++中的一个关键字叫做explicit 
  • 它加在构造函数的前面进行修饰,有了它就不会发生上面的这一系列事儿了,它会【禁止类型转换】
explicit Date(int year) :_year(year) {} 

 🍍多参构造函数

对于上面所讲的都是基于单参的构造函数,接下去我们来瞧瞧多参的构造函数 
//多参构造函数 Date(int year, int month ,int day = 31) :_year(year) ,_month(month) ,_day(day) {} 
  • 根据从右往左缺省的规则,我们在初始化构造的时候要给到2个参数,d1没有问题传入了两个参数,但是若是像上面那样沿袭单参构造函数这么去初始化还行得通吗?很明显不行,编译器报出了错误

 💬小蛋:那要怎么办呀,对于一定要传入多参数进行构造的场景

  •  这个时候就要使用到我们C++11中的新特性了,在对多参构造进行初始化的时候在外面加上一个{}就可以了,可能你觉得这种写法像是C语言里面结构体的初始化,但实际不是,而是在调用多参构造函数
Date d2 = { 2023, 3 }; 
  • 不仅如此,对于下面这种也同样适用,调用构造去产生一个临时对象
const Date& d3 = { 2024, 4 }; 
 那要如何去防止这样的隐式类型转换发生呢,还是可以使用到explicit关键字吗?
//多参构造函数 explicit Date(int year, int month ,int day = 31) :_year(year) ,_month(month) ,_day(day) {} 
  • 可以看到,加上explicit关键字做修饰,同样可以起到【禁止类型转换】的作用
  • 还有一种例外,当缺省参数从右往左给到两个的时候,此时只需要传入一个实参即可,那也就相当于是单参构造explicit关键字依旧可以起到作用·
explicit Date(int year, int month = 3,int day = 31) :_year(year) ,_month(month) ,_day(day) {} 

✨为什么需要explicit关键字? 

所以对于可读性不是很好的代码,可以使用explicit修饰构造函数,将会禁止构造函数的隐式转换 

✨ 怎么使用explicit关键字?

         explicit关键字在C++中只能用于修饰类的构造函数,它用来修饰只有一个参数的类构造函数,以表明该构造函数是显式的,而非隐式的。

        只要在构造函数名前加上explicit就能禁止类对象之间的隐式转换、禁止隐式调用拷贝构造函数。

四、总结 

 五、共勉

  以下就是我对C++ explicit关键字的理解,如果有不懂和发现问题的小伙伴,请在评论区说出来哦,同时我还会继续更新对C++ 的理解,请持续关注我哦!!!

Read more

优选算法——位运算

👇作者其它专栏 《数据结构与算法》《算法》《C++起始之路》 1.前要知识 《位操作符的妙用》 2.相关题解 2.1判定字符是否唯一 算法思路: 利用【位图】的思想,每一个【比特位】代表一个【字符】,一个int类型的变量的32位足够表示所有的小写字母。比特位里若为0,表示这个字符没有出现过;若为1,表示该字符出现过。 可以用一个【整数】来充当【哈希表】。 class Solution { public: bool isUnique(string astr) { //利用鸽巢原理优化 if(astr.size()>26) return false; int bitmap=0; for(auto i:

By Ne0inhk

算法优化:提升Lite-Avatar实时性的关键数据结构

算法优化:提升Lite-Avatar实时性的关键数据结构 1. 引言 实时数字人交互正成为AI应用的新趋势,但要做到真正的实时响应并不容易。想象一下,当你和数字人对话时,如果它的嘴型总是慢半拍,或者表情跟不上你的语音节奏,那种体验会有多糟糕。Lite-Avatar作为一款轻量级实时数字人引擎,面临着如何在有限计算资源下实现毫秒级响应的挑战。 传统的数字人渲染往往需要大量的计算资源,导致延迟较高,难以满足实时交互的需求。Lite-Avatar通过精心设计的数据结构和算法优化,成功将渲染延迟控制在50毫秒以内,这背后有着怎样的技术奥秘?本文将带你深入探索那些让Lite-Avatar如此高效的关键数据结构。 2. 实时性挑战与优化思路 2.1 数字人渲染的实时性要求 实时数字人交互对延迟有着极其严格的要求。根据人类感知研究,当延迟超过100毫秒时,用户就能明显感觉到音画不同步。而要实现自然的对话体验,延迟需要控制在50毫秒以内。这意味着从音频输入到画面输出的整个处理链路必须在极短时间内完成。 Lite-Avatar面临的挑战包括:音频特征提取、表情预测、口型同步、画面渲染等

By Ne0inhk

优选算法——二分查找

👇作者其它专栏 《数据结构与算法》《算法》《C++起始之路》 二分查找相关题解 1.二分查找 算法思路: a.定义left,right指针,分别指向数组的左右区间。 b.找到待查找区间的中间点mid,找到后分三种情况讨论:         i.arr[mid]==target说明正好找到,返回mid的值;         ii.arr[mid]>target说明[mid,right]这段区间都是大于target的,因此舍去右边区间,在左边[left,mid-1]的区间继续查找,即让right=mid-1,然后重复b过程;         iii.arr[mid]<target说明[left,mid]这段区间的值都是小于target的,因此舍去左边区间,在右边区间[mid+1,right]

By Ne0inhk
【算法通关指南:算法基础篇】二分算法:1.在排序树组中查找元素的第一个和最后一个位置 2.牛可乐和魔法封印

【算法通关指南:算法基础篇】二分算法:1.在排序树组中查找元素的第一个和最后一个位置 2.牛可乐和魔法封印

🔥小龙报:个人主页 🎬作者简介:C++研发,嵌入式,机器人方向学习者 ❄️个人专栏:《算法通关指南》 ✨ 永远相信美好的事情即将发生 文章目录 * 前言 * 一、二分算法 * 二、在排序树组中查找元素的第一个和最后一个位置 * 2.1题目 * 2.2 算法原理 * 2.3代码 * 三、牛可乐和魔法封印 * 3.1题目 * 3.2 算法原理 * 3.3代码 * 总结与每日励志 前言 本专栏聚焦算法题实战,系统讲解算法模块:以《c++编程》,《数据结构和算法》《基础算法》《算法实战》 等几个板块以题带点,讲解思路与代码实现,帮助大家快速提升代码能力ps:本章节题目分两部分,比较基础笔者只附上代码供大家参考,其他的笔者会附上自己的思考和讲解,希望和大家一起努力见证自己的算法成长 一、

By Ne0inhk