C++ cast
excerpted from Type conversions
K&R Section 2.7 p59 对type conversion 的解释:
The precise meaning of a cast is as if the expression were assigned to a variable of the specified type, which is then used in place of the whole construction.
(类型名) 表达式
将被转换的表达式赋值给指定类型的变量,然后用该变量替代上述语句
PART I Implicit conversion 隐式转换
1. fundamental data types 基本类型 (numeric, bool, some pointer)
精度损失: double -> int
2. non-fundamental types 非基本类型
1. NULL指针可以转换为任意类型
2. 任何类型指针可以转换为void *
3. 指针向上转换: 指针派生类的指针可以转换为其基类的指针
(注: pointers to a derived class can be converted to a pointer of an accessible and unambiguous base class, without modifying its const
or volatile
qualification.)
3. 类的的隐式转换
1.单参数构造函数
2.赋值运算符
3.类型转换运算符
PART II 显示转换
1. explicit 关键字, 防止不必要的隐式转换
explicit 构造函数(...) /* 在构造函数之前加explicit */
2. type casting
("coerced") 强制
convert any pointer into any other pointer type 任意类型转换为其它任意类型
1. functional notaion: y = int (x);
2. c-like notaion: y = (int)x;
3. casting operators 运算符 用来控制类的转换 (多涉及指针和类)
4种运算符 动态,静态,
1.dynamic_cast
两种转换:
upcast (converting from pointer-to-derived to pointer-to-base)
downcast (convert from pointer-to-base to pointer-to-derived)
dynamic_cast
can only be used with pointers and references to classes (or with void*
). Its purpose is to ensure that the result of the type conversion points to a valid complete object of the destination pointer type.
只能用于指针和引用 或 void *,确保转换结果指向目标类型的完整的合法的对象 (type-safety checks 类型安全检查)
//示例代码
// dynamic_cast #include <iostream> #include <exception> using namespace std; class Base { virtual void dummy() {} }; class Derived: public Base { int a; }; int main () { try { Base * pba = new Derived; Base * pbb = new Base; Derived * pd; pd = dynamic_cast<Derived*>(pba); // 转换成功, 因为pba指向完整的Deived对象 if (pd==0) cout << "Null pointer on first type-cast.\n"; pd = dynamic_cast<Derived*>(pbb); // 转换失败,返回NULL pbb指向基类对象 如果是转换引用(reference)类型失败,则抛出异常bad_cast
if (pd==0) cout << "Null pointer on second type-cast.\n"; } catch (exception& e) {cout << "Exception: " << e.what();} return 0; }
requires Run-Time Type Information (RTTI) to keep track of dynamic types
2.static_cast 类似于dynamic_cast, 可以upcast和downcast,但不做type-safety checks(交由程序员决定,因此省去了检查的开销(overhead))
class Base {}; class Derived: public Base {}; Base * a = new Base; Derived * b = static_cast<Derived*>(a); // 合法的代码, 但可能在解引用指针时导致runtime errors
void *转换为任意类型
整形值,浮点值,枚举类型转为枚举类型
3.reinterpret_cast 从任意类型到任意类型,即使类型毫不相关,既不检查指针指向的对象,也不检查指针的类型.
converts any pointer type to any other pointer type
The operation result is a simple binary copy of the value from one pointer to the other.操作结果就是简单的对指针按位复制
class A { /* ... */ }; class B { /* ... */ }; A * a = new A; B * b = reinterpret_cast<B*>(a); // 代码合法, 但don't make sense. 解引用b将是不安全的.
4.const_cast
对指针的const的操作,加上const或者去除cosnt
作用:将一个const指针传给非const的形参
// const_cast #include <iostream> using namespace std; void print (char * str) // 如果传入一个const指针, 不经转换的话会报错 { cout << str << '\n'; } int main () { const char * c = "sample text"; print ( const_cast<char *> (c) ); // 相当于传入了移除const的临时变量作为参数, 但如果函数写指针指向的对象将导致未定义的行为 return 0; }
PART III
typeid运算符, 检查表达式的类型
typeid (expression)
返回值:typeinfo类型的常量, typeinfo定义在<typeinfo>头文件中
通过==和!=比较typeinfo类型的变量
通过成员函数name()返回描述数据类型名或类名的字符串
// typeid #include <iostream> #include <typeinfo> using namespace std; int main () { int * a,b; a=0; b=0; if (typeid(a) != typeid(b)) //可以通过==和!=比较typeinfo类型的变量 { cout << "a and b are of different types:\n"; cout << "a is: " << typeid(a).name() << '\n'; cout << "b is: " << typeid(b).name() << '\n'; } return 0; }
a and b are of different types: a is: int * b is: int
When typeid
is applied to an expression whose type is a polymorphic class, the result is the type of the most derived complete object
当typeid用于多态类型时,结果是最接近派生的类的类型
// typeid, polymorphic class #include <iostream> #include <typeinfo> #include <exception> using namespace std; class Base { virtual void f(){} }; class Derived : public Base {}; int main () { try { Base* a = new Base; Base* b = new Derived; cout << "a is: " << typeid(a).name() << '\n'; cout << "b is: " << typeid(b).name() << '\n'; cout << "*a is: " << typeid(*a).name() << '\n'; cout << "*b is: " << typeid(*b).name() << '\n'; } catch (exception& e) { cout << "Exception: " << e.what() << '\n'; } return 0; }
a is: class Base * b is: class Base * *a is: class Base *b is: class Derived