C/C++编程:显式构造函数(explicit )

1059 篇文章 280 订阅

引入

如果类具有带一个参数的构造函数,或是如果除了一个参数之外的所有参数都具有默认值,则参数类型可以隐式转换为类类型(这样的构造函数也叫做隐式构造函数)。 例如,如果 Box 类具有一个类似于下面这样的构造函数:

Box(int size): m_width(size), m_length(size), m_height(size){}

可以初始化 Box,如下所示:

Box b = 42;

这类转换可能在某些情况下很有用,但更常见的是,它们可能会导致代码中发生细微但严重的错误。 作为一般规则,应使用explicit 在构造函数 (和用户定义的运算符) 上使用关键字,以防止这种隐式类型转换:(也就是显式构造函数)

explicit Box(int size): m_width(size), m_length(size), m_height(size){}

构造函数是显式函数时,此行会导致编译器错误:ShippingOrder so(42, 10.8);

作用

如果构造函数中带有explicit,则它只能用于初始化和显式类型转换。比如:

class Date{
	int d, m, y;
public:
	explicit Date(int dd = 0, int mm = 0, int yy = 0);
};;

Date d1{15};          //正确,被看成是显式类型转换
Date d2 = Date{15};   //正确,被看成是显式类型转换
Date d3 = {15};       //error:=初始化不能进行隐式类型转换
Date d4 = 15;         //error:=初始化不能进行隐式类型转换

void f(){
	my_fct(15);       //error:参数传递不能进行隐式类型转换
	my_fct({15});     //error:参数传递不能进行隐式类型转换
	my_fnt(Date{15}); // ok :显式类型转换
}

用=进行初始化可以看作拷贝初始化。一般来说,初始化器的副本会被放入待初始化的对象。但是,如果初始化器是一个右值,这种拷贝可能会被优化掉,而采用移动操作。省略=会将初始化变为显式初始化。显式初始化也叫做直接初始化*

默认情况下,应该将单参数的构造函数声明为explicit。除非你有很好的理由(比如complex复数:如果忽略虚部,就会得到实数轴上的一个复数+)。如果定义隐式构造函数,那就写下原因。

如果一个构造函数声明为explicit而且定义在类外,则在定义中不能重复explicit:

class Date{
	int d, m, y;
public:
	explicit Date(int d);
};

Date::Date(int d) {...}  //ok
explicit Date::Date(int d) {...} //error

大多数explicit起很重要作用的构造函数都接受单一参数。但是,explicit也可以用于无参或多个参数的构造函数:

struct x{
	explicit x();
	explicit x(int, int);
};

x x0 = {};     //错误,隐式的
x x1 = {1, 2}; //错误,隐式的

x x3{};        //正确,显式的
x x4{1,2};     //正确,显式的

int f(x);

int i1 = f({});   //错误,隐式的
int i2 = f({1,2});   //错误,隐式的
int i3 = f(x{});   //正确,显式的
int i4 = f(x{1.2});   //正确,显式的

列表初始化也存在直接初始化和拷贝初始化的区别

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值