explicit构造函数

article/2025/9/17 21:33:36

转载于GGBeng大佬

链接在此

explicit构造函数

前面是扫盲部分,可直接看后面的精华部分。

扫盲

一、隐式的类类型转换

1. 转换构造函数

如果构造函数只接受一个实参,则它实际上定义了转换为此类类型的隐式转换机制

能通过一个实参调用的构造函数定义了一条从构造函数的参数类型向类类型隐式转换的规则

2. 从参数类型向类类型隐式转换的实例
//在Sales_data类中,接受string的构造函数和接受istream的构造函数分别定义了从这两种类型向Sales_data隐式转换的规则。
//即,在需要使用Sales_data的地方,我们可以使用string或istream作为替代。
Sales_data total("9-999-99999-9", 2, 25.0);
string book = "9-999-99999-9";
//构造一个临时的Sales_data对象,其units_sold和revenue等于0,bookNo等于book
total.combine(book);
//我们用一个string实参调用了Sales_data的combine成员。
//在该调用中,编译器用给定的string自动创建了一个Sales_data对象,这个新生成的临时对象被传递给combine

【从istream到Sales_data的转换】

//使用istream构造函数创建一个函数传递给combine
total.combine(cin);
//隐式地把cin转换成Sales_data,这个转换执行了接受一个istream的Sales_data构造函数
//该构造函数通过读取标准输入创建了一个临时的Sales_data对象,随后将得到的对象传递给combine
  1. 编译器只会自动地执行一步类型转换
//下面的代码隐式地使用了两种转换规则(错误)
//错误:需要用户定义的两种转换
//(1):把"9-999-99999-9"转换成string
//(2):再把这个临时的string转换成Sales_data
total.combine("9-999-99999-9");
//可以显式地把字符串转换成string或者Sales_data对象
//正确:显式地转换成string,隐式地转换成Sales_data
total.combine(string("9-999-99999-9"));
//正确:隐式地转换成string,显式地转换成Sales_data
total.combine(Sales_data("9-999-99999-9"));

二、抑制构造函数定义的隐式转换

1. 将构造函数声明为explicit 来阻止类类型隐式转换

构造函数将不能隐式地创建Sales_data对象

2. 关键字explicit 只对一个实参的构造函数有效

需要多个实参的构造函数不能用于执行隐式转换

3. explicit 构造函数只能用于直接初始化

发生隐式转换的一种情况是:执行拷贝形式的初始化时(使用=)

string book = "9-999-99999-9";
//正确:直接初始化
Sales_data total(book);
//错误:不能将explicit构造函数用于拷贝形式的初始化过程
Sales_data total = book;
4. 在类内声明构造函数时使用explicit 关键字,在类外部定义时不应重复
class Sales_data{
public:Sales_data() = default;Sales_data(const string &s, unsigned n, double p): bookNo(s), units_sold(n), revenue(p*n);explicit Sales_data(const string &s): bookNo(s) {}explicit Sales_data(istream &)
};

三、例题

1. 说明接受一个string 参数的Sales_data 构造函数是否应该是explicit 的,并解释这样做的优缺点。

答:这个随便,因为这是一把双刃剑

  • 不带explicit的优点:可以从构造函数的参数类型向类类型隐式转换

  • 带explicit的优点:任何构造函数(尤其是带一个参数的)都不能隐式地创建类对象

  • 带explicit的缺点:该构造函数只能以直接初始化的形式使用

2. vector 将其单参数的构造函数定义成explicit 的,而string则不是,你觉得原因何在?

答:string接受的单参数是const char*类型,如果我们得到了一个常量指针,则把它看做string对象是自然而然的过程,编译器自动把参数类型转换成类类型也非常符合逻辑,因此我们无须指定为explicit。

与string相反,vector接受的单参数是int类型,这个参数的原意是指定vector的容量。如果我们在本来需要vector的地方提供一个int值并且希望这个int值自动转换成vector,则这个过程显得比较牵强,因此把vector的单参数构造函数定义成explicit的更加合理。

例如:定义为explicit是为了防止隐式的类型转换

void fun(vecor<int> vi);
fun(10);        //如果允许这样,那就意味不明了

四、更新

1. 如果我们使用的初始化值要求通过一个explicit 的构造函数来进行类型转换,那么使用拷贝初始化还是直接初始化就很关键了:
vector<int> v1(10);       //正确:直接初始化
vector<int> v2 = 10;  //错误:接受大小参数的构造函数是explicit的
void f(vector<int>);  //f的参数进行拷贝初始化
f(10);                  //错误:不能用一个explicit的构造函数拷贝一个实参
f(vector<int>(10));       //正确,从一个int直接构造一个临时vector

解读:直接初始化v1是合法的,而拷贝初始化v2则是错误的,因为vector的接受单一大小参数的构造函数是explicit的(于是10就不能隐式转换为vector<int>类型,当然不能赋值给v2了)。

同理,当传递一个实参或从函数返回一个值时,我们不能隐式使用一个explicit构造函数。如果希望使用explicit构造函数,那就需要显式地使用,正如最后一行代码那样。

2. 我们可以使用new返回的指针来初始化智能指针,但接受指针参数的智能指针构造函数是explicit的,因此我们不能够将一个内置指针隐式转换为一个智能指针,而必须使用直接初始化形式来初始化一个智能指针
//正确,使用了直接初始化形式,shared_ptr有相应的构造函数
shared_ptr<int> p(new int(1024));
//错误,赋值符右侧是内置指针,不能隐式转换为智能指针
shared_ptr<int> p = new int(1024);

/* 精华 */

一、单参数构造函数——一步类类型转换

当类中含有单参数构造函数时,则表明定义了一条从构造函数的参数类型向类类型隐式转换
#include <iostream>using namespace std;class A {
public:A() = default;A(string str) : s(str) {}       // 单参数void print(const A &a){cout << a.i << " " << a.d << " " << a.s << endl;}private:int i = 2;double d = 3.14;string s = "haha";
};int main()
{A a;string ss("trans");a.print(ss);            // string类型转换为A类型return 0;
}

输出:

二、explicit构造函数

破坏上面的那条规则
只能用于直接初始化
class A {
public:A() = default;explicit A(string str) : s(str) {}      // 单参数
private:int i = 2;double d = 3.14;string s = "haha";
};int main()
{string ss("explicit");A a(ss);
//  A a1 = ss;      // 错误return 0;
}

注:发生隐式转换的一种情况是当我们执行拷贝形式的初始化时(使用=,即上面代码行中的),故此处发生错误。


http://chatgpt.dhexx.cn/article/GfFTxEpq.shtml

相关文章

详解 c++ 关键字 explicit

用了很久的C 了&#xff0c;今天突然被小伙伴问道&#xff0c;构造函数前的explicit 关键字什么作用&#xff0c;于是自己也只能支支吾吾的说出“为了显式调用……”很尴尬啊……典型的知道所以然不知道其所以然……好吧&#xff0c;搜搜资料好好地充充电…… 首先说定义&#…

explicit的用法

explicit的用法 explicit关键字的作用是&#xff1a;禁止隐式调用类的单参数构造函数&#xff0c;主要禁用以下两种操作&#xff1a; 禁止隐式调用拷贝构造函数 禁止类对象之间的隐式转换 类对象之间的隐式转换是指利用一个已经存在的其它类型的对象来创建本类的新对象&#…

C++中的explicit关键字介绍

C中的关键字explicit主要是用来修饰类的构造函数&#xff0c;被修饰的构造函数的类&#xff0c;不能发生相应的隐式类型转换&#xff0c;只能以显示的方式进行类型转换。类构造函数默认情况下声明为隐式的即implicit。 隐式转换即是可以由单个实参来调用的构造函数定义了一个从…

C++中explicit的作用及用法

仅含一个参数的构造函数和除了第一个参数外其余参数都有默认值的多参构造函数承担了两个角色。 1. 是个构造函数&#xff1b;2 .是个默认且隐含的类型转换操作符。 explicit是个C关键字&#xff0c;其作用是指定仅有一个参数或除第一个参数外其它参数均有默认值的类构造函数…

C++ explicit

C提供了关键字explicit&#xff0c;声明为explicit的构造函数不能在隐式转换中使用。 1)C的类型转换分为两种&#xff0c;一种为隐式转换&#xff0c;另一种为显式转换。 2)C中应该尽量不要使用转换&#xff0c;尽量使用显式转换来代替隐式转换。 1隐式转换 定义&#xff1a…

C++ 中explicit的作用及用法(虽然简单,但是还是有用的)

目录 Cexplicit&#xff08;官网的说法&#xff09; explicit specifier Cexplicit 清楚的说法&#xff08;建议英文不好的从这里开始食用哦&#xff09; explicit作用: explicit使用注意事项: Cexplicit使用的例子&#xff08;建议喜欢自己敲代码实验的从这里开始食用哦&…

C++之explicit的作用介绍

1、C中的关键字explicit主要是用来修饰类的构造函数&#xff0c;被修饰的构造函数的类&#xff0c;不能发生相应的隐式类型转换&#xff0c;只能以显示的方式进行类型转换。类构造函数默认情况下声明为隐式的即implicit。隐式转换即是可以由单个实参来调用的构造函数定义了一个…

explicit关键字详解

在C中&#xff0c;explicit关键字用来修饰类的构造函数&#xff0c;被explicit修饰的类的构造函数&#xff0c;不能发生相应的隐式类型转换&#xff0c;只能以显示的方式进行类型转换。 explicit使用注意事项: explicit 关键字只能用于类内部的构造函数声明上。 explicit 关…

74HC244;74HCT244——三态八路缓冲器/线路驱动器

1.特点&#xff1a; 2.引脚及封装&#xff1a; 3.引脚定义&#xff1a; 解释&#xff1a; output enable input (active LOW)输出使能&#xff0c;低电平有效 data input&#xff1a;数据输入 bus output:总线输出 4.使用逻辑&#xff1a; 解释&#xff1a; L&#xff1a;…

三态门(三态缓冲器)的工作原理

转载于http://www.eeworld.com.cn/mcu/article_2017102035218.html 为减少信息传输线的数目&#xff0c;大多数计算机中的信息传输线均采用总线形式&#xff0c;即凡要传输的同类信息都走同一组传输线&#xff0c;且信息是分时传送的。在计算机中一般有三组总线&#xff0c;即数…

2021-05-18

TTL集成门电路——三态门(与非门) 1、三态门的三种输出状态:高电平(逻辑1&#xff09;&#xff0c;低电平(逻辑0&#xff09;&#xff0c;高阻态(电阻大&#xff0c;可以视为开路) 2、三态门真值表及逻辑符号: !3、三态门的工作电路: 4、三态门的工作原理&#xff1a; EN为三…

锁存器、触发器、寄存器和缓冲器的区别

目录 一、锁存器 二、触发器 三、寄存器 四、移位寄存器 五、总线收发器/缓冲器 六、锁存器与触发器的区别 七、D触发器和D锁存器的区别 八、寄存器与锁存器的区别 一、锁存器 锁存器&#xff08;latch&#xff09;---对脉冲电平敏感&#xff0c;在时钟脉冲的电平作用…

三态门与高阻态

转自&#xff1a;https://blog.csdn.net/lin200753/article/list/4 高阻态这是一个数字电路里常见的术语&#xff0c;指的是电路的一种输出状态&#xff0c;既不是高电平也不是低电平&#xff0c;如果高阻态再输入下一级电路的话&#xff0c;对下级电路无任何影响&#xff0c;…

三态门与高阻状态

三态门&#xff0c;是指逻辑门的输出除有高、低电平两种状态外&#xff0c;还有第三种状态——高阻状态的门电路。高阻态相当于隔断状态&#xff08;电阻很大&#xff0c;相当于开路&#xff09;。 三态门都有一个EN控制使能端&#xff0c;来控制门电路的通断。 可以具备这三种…

【微机原理与接口技术】简单易学的 简单接口芯片—— 三态门 74LS244和 锁存器 74LS273

作者&#xff1a;MiTu_-_ 本帖内容著作权归作者所有&#xff0c;转载请务必保留本文链接 接口电路的基本构成 CPU通过接口与外部设备的连接示意图如下&#xff1a; 负责把信息从外部设备传入 CPU 的接口&#xff08;端口&#xff09;叫做输入接口&#xff08;端口&#xff09…

三态门——概念,作用,原理

介绍一下三态门的概念、作用、原理 目录 三态门的概念 三态门的作用 实现总线结构 实现双向数据传输 三态门的原理 三态门的概念 三态门是指逻辑门的输出有三种状态&#xff1a;高电平状态、低电平状态、高阻状态。 其中&#xff0c;高阻状态相当于隔离状态&#xff08;…

数字IC设计中的三态门原理

数字电路中的三态门 可参考另外一篇博客数字电路基础知识——CMOS门电路 (与非门、或非、非门、OD门、传输门、三态门) 三态门除了高低电平&#xff0c;还有第三个状态——高阻态。 三态门&#xff08;Three-state gate&#xff09;是一种重要的总线接口电路。也常常出现在芯片…

计算机电源缓冲器,集成电路中缓冲器的作用

描述 缓冲器的概念 缓冲器在不同的领域有不同的含义。 在计算机领域&#xff0c;缓冲器指的是缓冲寄存器&#xff0c;它分输入缓冲器和输出缓冲器两种。前者的作用是将外设送来的数据暂时存放&#xff0c;以便处理器将它取走&#xff1b;后者的作用是用来暂时存放处理器送往外设…

三态门介绍

如下图&#xff0c;为两种形式的三态门&#xff0c;&#xff08;a&#xff09;和&#xff08;b&#xff09;一致&#xff1b;&#xff08;c&#xff09;和&#xff08;d&#xff09;一致。 对于图&#xff08;a&#xff09;其真值表如下&#xff1a; 对于图&#xff08;b&#…