Del*_*llo 12 c++ type-conversion
在哪里可以找到一篇关于C++类型转换的非常容易理解的文章,涵盖了所有类型(促销,隐式/显式等)?
我已经学习了一段时间的C++,例如,虚拟函数机制对我来说比这个主题更清晰.我的观点是,这是因为教科书的作者太复杂了(参见Stroustroup的书等等).
MSa*_*ers 21
(道具给Crazy Eddie获得第一个答案,但我觉得它可以更清晰)
类型转换可能有两个主要原因.一个是因为你写了一个显式表达式,比如static_cast<int>(3.5).另一个原因是您在编译器需要其他类型的位置使用了表达式,因此它将为您插入转换.Eg 2.5 + 1将导致从1(整数)到1.0(双精度)的隐式转换.
只有有限数量的显式表格.首先,C++有4个名为版本:static_cast,dynamic_cast,reinterpret_cast和const_cast.C++还支持C风格的演员表(Type) Expression.最后,有一个"构造函数式"演员Type(Expression).
任何好的介绍性文本都记录了4种命名形式.C风格的演员阵容扩展为a static_cast,const_cast或者reinterpret_cast,"构造函数式"演员阵容是a的简写static_cast<Type>.但是,由于解析问题,"构造函数样式"强制转换需要一个单一名称的单一标识符; unsigned int(-5)或者const float(5)不合法.
枚举隐式转换可能发生的所有上下文要困难得多.由于C++是一种类型安全的OO语言,因此在许多情况下,在需要类型B的上下文中有对象A.示例是内置运算符,调用函数或按值捕获异常.
在所有情况下,隐式和显式,编译器将尝试查找转换序列.转换序列是一系列步骤,可以使您从类型A转换为类型B.编译器选择的确切转换序列取决于强制类型.A dynamic_cast用于执行已检查的Base-to-Derived转换,因此步骤是检查Derived是否继承自Base,通过哪个中间类.const_cast可以删除const和volatile.在a的情况下static_cast,可能的步骤是最复杂的.它将在内置算术类型之间进行转换; 它将Base指针转换为Derived指针,反之亦然,它将考虑类构造函数(目标类型)和类转换运算符(源类型),它将添加const和volatile.显然,这些步骤中的相当一部分是正交的:算术类型永远不是指针或类类型.此外,编译器最多只使用一次步骤.
正如我们前面提到的,某些类型转换是显式的,而其他转换是隐式的.这很重要,static_cast因为它在转换序列中使用用户定义的函数.编译器通过的一些转换步骤可以标记为explicit(在C++ 03中,只有构造函数可以).explicit对于隐式转换序列,编译器将跳过(无错误)任何转换函数.当然,如果没有其他选择,编译器仍然会给出错误.
诸如char和之类的整数类型short可以转换为"更大"类型,例如int和long,并且较小的浮点类型可以类似地转换为更大的类型.有符号和无符号整数类型可以相互转换.整数和浮点类型可以相互更改.
由于C++是一种OO语言,因此Base和Derived之间的关系很多.在这里理解实际对象,指针和引用之间的区别非常重要(特别是如果你来自.Net或Java).首先是实际的对象.它们只有一种类型,您可以将它们转换为任何基类型(暂时忽略私有基类).转换会创建一个基类型的新对象.我们称之为"切片"; 派生的部分被切掉.
当您有指向对象的指针时,存在另一种类型的转换.您始终可以将a转换Derived*为a Base*,因为在每个Derived对象中都有一个Base子对象.C++将自动将Base with Derived的正确偏移量应用于指针.此转换将为您提供一个新指针,但不是新对象.新指针将指向现有的子对象.因此,强制转换永远不会切掉对象的派生部分.
另一种方式的转换比较棘手.通常,并非每个Base*都指向Derived对象内的Base子对象.基础对象也可能存在于其他地方.因此,转换可能会失败.C++为您提供了两个选项.要么你告诉编译器你确定你通过a指向Derived中的子对象static_cast<Derived*>(baseptr),或者要求编译器检查dynamic_cast<Derived*>(baseptr).在后一种情况下,结果将是nullptrif baseptr实际上不指向Derived对象.
对于Base和Derived的引用,同样适用,除了dynamic_cast<Derived&>(baseref):它将抛出std::bad_cast而不是返回空指针.(没有空引用这样的东西).
有两种方法可以定义用户转换:通过源类型和目标类型.第一种方法涉及operator DestinatonType() const在源类型中定义成员.请注意,它没有明确的返回类型(它始终是DestinatonType),而且它是const.转换永远不应该更改源对象.只需添加多个运算符,类就可以定义几种可以转换的类型.
第二种类型的转换,通过目标类型,依赖于用户定义的构造函数.T::T可以使用一个类型的参数调用的构造函数U可用于将U对象转换为T对象.如果该构造函数具有其他默认参数并不重要,如果U参数通过值或引用传递也不重要.但是,如前所述,如果T::T(U)是explicit,则不会在隐式转换序列中考虑它.
由于用户定义的转换序列,两种类型之间的多个转换序列是可能的.由于这些本质上是函数调用(对用户定义的运算符或构造函数),因此通过不同函数调用的重载解析来选择转换序列.