C++ explicit 构造函数

本文探讨了C++中单参数构造函数如何定义从参数类型到类类型的隐式转换,通过Sales_item类的构造函数示例展示了如何使用explicit关键字来避免不期望的隐式转换。
本文主要参考《C++ Primer 4e》第12.4.4小节,以及《Effective C++ 3e》第0章。


可以用单个实参来调用的构造函数定义了从形参类型到该类型的一个隐式转换。这句话有点绕,我们来看一个例子。

class Sales_item {
public:
	Sales_item() : units_sold(0), revenue(0.0) {}
	// default argument for book is the empty strings
	Sales_item(const std::string &book = "") :
		isbn(book), units_sold(0), revenue(0.0) {}
	Sales_item(std::istream &is);
	bool same_isbn(const Sales_item &rhs) const
	{ return isbn == rhs.isbn; }
private:
	std::string isbn;
	unsigned units_sold;
	double revenue;
};

这里定义了三个构造函数,后面的两个构造函数都定义了一个隐式转化。因此,在期待一个Sales_item类型对象的地方,可以使用一个string或一个istream:

Sales_item item;
string null_book = "9-999-99999-9";
// ok: builds a Sales_item with 0 units_sold and revenue from
// and isbn equal to null_book
item.same_isbn(null_book);

same_isbn期待一个Sales_item对象,于是编译器在此处接受一个string对象null_book,并调用Sales_item(const std::string &book)生成一个新的Sales_item对象,该新对象被传递给same_isbn。

更成问题的是从istream到Sales_item的隐式转化:

// ok: uses the Sales_item istream constructor to build an object
// to pass to same_isbn
item.same_isbn(cin);

这段代码将cin隐式转化为Sales_item对象。

这些行为在多数情况下都不是我们想要的,如何抑制这种情况?

可以通过将构造函数声明为explicit,来防止在需要隐式转化的上下文使用构造函数:

class Sales_item {
public:
	Sales_item() : units_sold(0), revenue(0.0) {}
	// default argument for book is the empty strings
	explicit Sales_item(const std::string &book = "") :
		isbn(book), units_sold(0), revenue(0.0) {}
	explicit Sales_item(std::istream &is);
	bool same_isbn(const Sales_item &rhs) const
	{ return isbn == rhs.isbn; }
private:
	std::string isbn;
	unsigned units_sold;
	double revenue;
};

explicit关键字只能用于类内部的构造函数声明上,在类的定义体外部所做的定义上不再重复它:

// error: explicit allowed only on constructor declaration in class header
explicit Sales_item::Sales_item(istream &is)
{
	is >> *this;	// use Sales_item input operator to read the members
}

通常,除非有明显的理由想要定义隐式转化,否则,单形参构造函数应该为explicit。将构造函数设置为explicit可以避免错误,并且当转换用用时,用户可以显式地构造对象。
### 回答1: 我可以解释explicit构造函数的用法。 explicit构造函数C++中的一种特殊构造函数,它可以防止类的实例被转换,从而避免出现错误。它通常被定义为一个具有const限定符的成员函数,这意味着它不能修改类的成员变量。 ### 回答2: 在C++中,构造函数被用于创建对象并初始化其成员变量。然而,有时我们可能希望禁止地将某个类的一个参数类型转换为该类的对象类型,这时就可以使用explicit关键字来声明构造函数。 当我们使用explicit关键字声明一个构造函数时,它将不再能够进行类型转换。只有在显地调用构造函数时,才能使用该构造函数创建一个对象。 explicit关键字的使用可以避免一些潜在的问题和错误的发生。它可以防止编译器地将一个参数类型转换为对象类型,以免引发意想不到的结果。 举个例子,假设有一个类A,其中有一个带有一个int参数构造函数。如果我们不使用explicit关键字来声明该构造函数,那么在编译器看来,一个int类型的变量可以被自动转换为一个A类型的对象。这种转换可能会导致意想不到的结果和错误的发生。 但是如果我们使用explicit关键字来声明该构造函数,那么编译器将不再允许转换,只能通过显调用构造函数来创建对象。 总之,explicit关键字用于禁止地将一个参数类型转换为对象类型。它可以避免潜在的问题和错误,使代码更加可靠和健壮。 ### 回答3: 在C++中,构造函数(Constructor)是一种特殊类型的成员函数,用于在创建对象时初始化对象的数据成员。当我们定义一个类时,可以定义一个或多个构造函数来满足不同的对象创建需求。其中,explicit是一个关键字,用于修饰构造函数explicit关键字的作用是防止转换,它只能用于构造函数(即只有一个参数构造函数)。当构造函数声明为explicit时,禁止编译器通过转换将该参数类型转换成对应的类类型。可以通过显调用构造函数进行对象的创建和转换。 举个例子,假设有一个类A,其中定义了一个构造函数A(int n),同时使用了explicit关键字进行修饰。如果没有explicit关键字修饰,则可以进行转换,比如可以使用A对象去初始化一个int类型的变量。但是,如果使用explicit修饰之后,编译器将不再允许转换,只能通过显进行构造和转换。 这种explicit用法可以避免一些不必要的类型转换带来的错误和混淆,能够增加程序的类型安全性。此外,explicit关键字还可以用于拒绝编译器进行多次转换,因为如果构造函数没有使用explicit关键字修饰,编译器可能会进行多次自动类型转换,导致程序的行为变得复杂和难以理解。 总结来说,当我们在定义构造函数时,如果希望限制使用转换创建对象的情况,就可以使用explicit关键字对构造函数进行修饰,以保证程序的可读性和类型安全性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值