C++学习笔记:数据类型相关typeid、cast
C++
是强类型语言,里面的每一个变量和表达式都有自己的类型。有了类型编译器就可以帮助进行类型检查,有错误就会报出来。
1.typeid
typeid
是一个运算符,用来返回一个变量(或者表达式、对象)的类型。typeid
定义在头文件typeinfo
中,因此使用的时候必须包含该头文件。使用语法是:
typeid(e);
举个栗子:
#include<iostream>
#include<typeinfo>
using namespace std;
class person
{
};
int main(int argc,char**argv)
{
int a = 10;
short b;
char c;
person d;
cout<<"type of int a = "<<typeid(a).name()<<endl;
cout<<"type of short b = "<<typeid(b).name()<<endl;
cout<<"type of char c = "<<typeid(c).name()<<endl;
cout<<"type of person d = "<<typeid(d).name()<<endl;
cout<<"type of typeid(a) = "<<typeid(typeid(a)).name()<<endl;
return 0;
}
输出:
type of int a = i
type of short b = s
type of char c = c
type of person d = 6person
type of typeid(a) = N10__cxxabiv123__fundamental_type_infoE
typeid
的深层次说明:
- 1.一个表达式的类型分静态类型(在编译器编译的时候就可以确定类型,大部分类型都是静态的,比如
int
、double
等)和动态类型(这个符号在运行的时候才能确定具体的类型,比如void*
),分别对应编译期和运行时类型决策系统。 - 2.
typeid
是C++
语言本身的特性,由编译器和库函数共同支撑。 - 3.
typeid
可用来返回静态类型,也可用来返回动态类型,它真正大用在运行时的动态类型检查。在引入类和继承后,并结合指针和引用后才能显现出来。
2.C++中的4中cast
2.1 静态转换static_cast
源生类型之间的隐式类型转换,可以用static_cast
来明确告知编译器,避免警告,转换后可能丢失精度,因此转换的正确性需要程序员自己保证。
举个栗子:
int main(int argc,char**argv)
{
int a = 88;
//char c = a;
char c = static_cast<char>(a);
cout<<c<<endl;
return 0;
}
输出:
X
static_cast
还用来将void*
类型的指针转为具体的指针类型,取回原有的指针类型。
举个栗子:
int main(int argc,char**argv)
{
int a = 88;
int* p1 = &a;
void* p2 = p1; //此时p2已经丢失了指针类型
int* p3 = static_cast<int*>(p2); //p3取回了类型
cout<<*p3<<endl;
return 0;
}
输出:
88
static_cast
也用于类层次结构中父类和子类之间指针和引用的转换,其中上行转换时安全的,而下行转换时不安全的。
总结:static_cast<>()
是编译时静态类型检查,使用static_cast
可以尽量发挥编译器的静态类型检查功能,但是并不能保证代码一定“正确”(譬如可能会丢失精度导致错误,可能经过void *
之后导致指针类型错误,可能下行转换导致访问错误)。static_cast
实际上只能解决很初级的编程问题,属于初级语法特性。
2.2 重新解释转换reintepret_cast
reintepret_cast
用于明确告知编译器该类型转换在编译时放行,正确性由程序员自己负责。reintepret_cast
转换前后对象(变量)在内存中的二进制数据并未发生任何变化,只是对这些二进制位的编译器类型标识发生了变化,或者说是编译器对这些二进制位的解析方式不同了。
reintepret_cast
一般用于将指针转成int或者回转,将A类型指针转为B类型指针等,它其实就是让C++
在本次转换中放弃严苛的编译器类型检查。
2.3 const_cast
cconst_cast
用来修改类型的const
或volatile
属性。
int main(int argc,char**argv)
{
const int a = 5;
// a=6; 编译报错
int* p=const_cast<int*>(&a);
*p=14;
cout<<*p<<endl;
return 0;
}
思考:const_cast
为什么能修改const
为非const
?因为const
变量不是物理上(将变量写在只读内存区)实现的,而是编译的时候由编译器保证不被修改的。
2.4 动态转换dynamic_cast
dynamic_cast
只用在父子class
的指针和引用访问时的转换中,尤其是下行转换时。dynamic_cast
属于一种运行时转换机制,运行时才能知道转换结果是NULL
(转换失败返回)还是有效对象(转换成功返回)。运行时确定对象类型RTTI
(run time type indentification)是一种需求,C++
有一套机制来实现。
4种
cast
转换总结:C
语言中一般都用隐式转换或强制类型转换解决,本质上是一种一刀切方案,全靠程序员自己把控。C++
中4种cast
转换实际上是细分了具体场景,让程序员在具体情况下显式的使用相应的cast
来转换,让编译器和运行时尽可能帮程序员把关。
3.C++的自动类型推导
3.1 auto关键字
auto
在C
中修饰局部变量,可以省略,完全无用。C++
中的auto
完全是一个新关键字,要求至少不低于C++11
标准来支撑。
auto
在编译器由编译器帮我们自动推导出变量(对象)类型,所以定义时必须初始化,auto
可以一次定义多个同类型的变量,但是不能一次定义多个类型不同的变量,这是auto
的类型推导机制决定的。
auto i = 5;
//则i被自动推导为int类型
auto a=4,b=5; //可以
auto x=4,y=5.5; //不可以
3.2 decltype关键字
decltype
是C++11
新增关键字,可以让编译器推导目标表达式的类型作为一种类型符使用。decltype(表达式)
作为类型定义变量不要求初始化。
int i =5;
decltype(i) j;
//则j的类型同i,是int类型
3.3 auto和decltype的对比
- 1.
auto
忽略顶层const
,而decltype
则保留const
。 - 2.
auto
作为类型占用符,而decltype
用法类似于sizeof
运算符。 - 3.对引用操作,
auto
推断出原有类型,decltype
推断出引用。 - 4.对解引用操作,
auto
推断出原有类型,decltype
推断出引用。 - 5.
auto
推断时会实际执行,decltype
不会执行,只做分析。