隐式的类类型转换

如果构造函数只接受一个实参,则它实际上定义了转换为此类类型的隐式转换机制,有时我们把这种构造函数称作转换构造函数。

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

例如,在Sales_data类中,接受string的构造函数和接受istream的构造函数分别定义了从这两种类型向Sales_data隐式转换的规则。也就是说,在需要使用Sales_data的地方,我们可以使用string或者istream作为替代:

构造函数:Sales_data(const string &s);
Sales_data(istream &);Sales_data &combine(const Sales_data&);

string null_book="9-999-99999-9";

//构造一个临时的Sales_data对象

//该对象的units_sold和revenue等于0,bookNo等于null_book

item.combine(null_book);

在这里我们用一个string实参调用了Sales_data的combine成员。该调用时合法的,编译器用给定的string自动创建一个Sales_data对象。新生成的这个(临时)Sales_data对象被传递给combine。因为combine的参数是一个常量引用,所以我们可以给该参数传递以临时量

 

只允许一步类类型转换

编译器只会自动地执行一步类型转换。例如,因为下面的代码隐式地使用了两种转换规则,所以它是错误的:

//错误:需要用户定义的两种转换:

//(1)把“9-999-99999-9”转换成string

//(2)再把这个(临时的)string转换成Sales_data

item.combine("9-999-99999-9");

如果我们想完成上述调用,可以显式地把字符串转换成string或者Sales_data对象:

//正确:显式地转换成string,隐式地转换成Sales_data

item.combine(string("9-999-99999-9"));

//正确:隐式地转换成string,显式地转换成Sales_data

item.combine(Sales_data("9-999-99999-9"));

 

类类型转换不是总有效

是否需要从string到Sales_data的转换依赖于我们对用户使用该转换的看法。在此例中,这种转换可能是对的。null_book中的string可能表示了一个不存在的ISBN编号。

另一个从istream到Sales_data的转换:

//使用istream构造函数创建一个函数传递给combine

item.combine(cin);

这段代码隐式地把cin转换成Sales_data,这个转换执行了接受一个istream的Sales_data构造函数。该构造函数通过读取标准输入创建了一个(临时的)Sales_data对象,随后将得到的对象传递给combine。

Sales_data对象是个临时量,一旦combine完成我们就不能再访问它了。实际上,我们构建了一个对象,先将它的值加到item中,随后将其丢弃。

 

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

在要求隐式转换的程序上下文中,我们可以通过将构造函数声明为explicit加以阻止:

class Sales_data{
public:
    Sales_data()=default;
    Sales_data(const std::string &s,unsigned n,double p):
                       bookNo(s),units_sold(n),revenue(p*n) {}
    explicit Sales_data(const std::string &s):bookNo(s)  {}
    explicit Sales_data(std::istream&);
//其他成员与之前的一致
};

此时,没有任何构造函数能用于隐式地创建Sales_data对象,之前的两种用法都无法通过编译:

item.combine(null_book);   //错误:string构造函数是explicit

item.combine(cin);       //错误:istream构造函数是explicit的

关键字explicit只对一个实参的构造函数有效。需要多个实参的构造函数不能用于执行隐式转换,所有无须将这些构造函数指定为explicit的。只能在类内声明构造函数时使用explicit关键字,在类外部定义时不应重复:

//错误:explicit关键字只允许出现在类内的构造函数声明处

explicit Sales_data::Sales_data(istream& is)

{

  read(is,*this);

}

 

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

发生隐式转换的一种情况是当我们执行拷贝形式的初始化时(使用=)。此时,我们只能使用直接初始化而不能使用explicit构造函数:

Sales_data item1(null_book);  //正确:直接初始化

Sales_data item2=null_book;   //错误:不能将explicit构造函数用于拷贝形式的初始化过程

注意:当我们使用explicit关键字声明构造函数时,它将只能以直接初始化的形式使用。而且,编译器将不会在自动转换过程中使用该构造函数。

 

为转换显式地使用构造函数

尽管编译器不会将explicit的构造函数用于隐式转换过程,但是我们使用这样的构造函数显式地强制进行转换“

//正确:实参是一个显式构造的Sales_data对象

item.combine(Sales_data(null_book));

//正确:static_cast可以使用explicit的构造函数

item.combine(static_cast<Sales_data>(cin));

在第一调用中,我们直接使用Sales_data的构造函数,该调用通过接受string的构造函数创建了一个临时的Sales_data对象。第二个调用,我们使用static_cast执行了显式的而非隐式的转换。其中,static_cast使用istream构造函数创建了一个临时的Sales_data对象

 

时间: 2024-10-28 16:00:28

隐式的类类型转换的相关文章

C#的隐式类型转换

在C#语言中,一些预定义的数据类型之间存在着预定义的转换.比如,从int类型转换到long类型.C#语言中数据类型的转换可以用分为两类:隐式转换(implicit conversions)和显式转换(explicit conversions).本章我们将详细介绍这两类转换. 6.1 隐式类型转换 隐式转换就是系统默认的.不需要加以声明就可以进行的转换.在隐式转换过程中,编译器无需对转换进行详细检查就能够安全地执行转换.比如从int类型转换到long类型就是一种隐式转换.隐式转换一般不会失败,转换

C++中通过重载避免隐式类型转换

以下是一段代码,如果没有什么不寻常的原因,实在看不出什么东西: class UPInt { // unlimited precision public: // integers 类 UPInt(); UPInt(int value); ...};//有关为什么返回值是const的解释,参见Effective C++ 条款21const UPInt operator+(const UPInt& lhs, const UPInt& rhs);UPInt upi1, upi2;...UPInt

浅析JavaScript中的隐式类型转换

        这篇文章主要是对JavaScript中的隐式类型转换进行了详细分析介绍,需要的朋友可以过来参考下,希望对大家有所帮助 如果把通过函数或方法调用,明确的将某种类型转换成另一种类型称为显示转换 ,相反则称为隐式类型转换 .google和维基百科中没有找到"显示类型转换","隐式类型转换"的字眼.暂且这么称呼.   一. 运算中存在的隐式类型转换    1, "+"运算符     代码如下: var a = 11, b = '22'; 

struct-c# 在一个实现了隐式转换的结构体进行强制类型转换时报错

问题描述 c# 在一个实现了隐式转换的结构体进行强制类型转换时报错 50C 如题,我有一个结构体,类似这样: public struct AInt{ private int _a; public int ToInt() { reurn _a; } public static implicit operator int(AInt value) { return value.ToInt(); } public static implicit operator AInt(int value) { _a

JavaScript隐式类型转换_javascript技巧

JavaScript的数据类型是非常弱的(不然不会叫它做弱类型语言了)!在使用算术运算符时,运算符两边的数据类型可以是任意的,比如,一个字符串可以和数字相加.之所以不同的数据类型之间可以做运算,是因为JavaScript引擎在运算之前会悄悄的把他们进行了隐式类型转换的,如下是数值类型和布尔类型的相加: 复制代码 代码如下: 3 + true; // 4 结果是一个数值型!如果是在C或者Java环境的话,上面的运算肯定会因为运算符两边的数据类型不一致而导致报错的!但是,在JavaScript中,只

浅析JavaScript中的隐式类型转换_javascript技巧

如果把通过函数或方法调用,明确的将某种类型转换成另一种类型称为显示转换 ,相反则称为隐式类型转换 .google和维基百科中没有找到"显示类型转换","隐式类型转换"的字眼.暂且这么称呼. 一. 运算中存在的隐式类型转换 1, "+"运算符 复制代码 代码如下: var a = 11, b = '22'; var c = a + b; 这里引擎将会先把a变成字符串"11"再与b进行连接,变成了"1122".

数据类型,隐式类型转换

 关于数据类型: 1.常量也是有类型的 常量数据大体分两类,一类是带点(实型,浮点型),一类是不带点叫整型. 编译器对带点,通常默认为double,不带点通常编译为int 2.对于数据   .2  默认分配其8个字节.   .2F/f   改默认存储为4个字节,12U,改默认为正数的表达范围.12L  改默认为L   关于隐式类型转换: 大数据赋给小变量的情况: A:一定会发生截断行为,以低字节对齐,开始截断. B:有可能会伴随发生数据丢失行为. 小数据赋给大变量 小数据赋给大变量,为了保证

c++隐式类型转换示例分享_C 语言

复制代码 代码如下: /*=============================================================================#     FileName: explicit_try.cc#         Desc: 验证含有一个参数的非explicit构造函数是否可以拷贝初始化=============================================================================*/#in

小心MySQL的隐式类型转换陷阱

1. 隐式类型转换实例 今天生产库上突然出现MySQL线程数告警,IOPS很高,实例会话里面出现许多类似下面的sql:(修改了相关字段和值) SELECT f_col3_id,f_qq1_id FROM d_dbname.t_tb1 WHERE f_col1_id=1226391 and f_col2_id=1244378 and f_qq1_id in (12345,23456,34567,45678,56789,67890,78901,89012,90123,901231,901232,90