目录
强制转换
static_cast
const_cast
reinterpret_cast
dynamic_cast
const关键字
修饰内置类型*
修饰指针类型*
类比
数组指针
指针数组
函数指针
指针函数
强制转换
C语言中的强制转换在C++代码中依然可以使用,这种C风格的转换格式非常简单
TYPE a = (TYPE)EXPRESSION;
但是c风格的类型转换有不少的缺点,有的时候用c风格的转换是不合适的,因为它可以在任意类型之间转换,比如你可以把一个指向const对象的指针转换成指向非const对象的指针,把一个指向基类对象的指针转换成指向一个派生类对象的指针,这两种转换之间的差别是巨大的,但是传统的c语言风格的类型转换没有区分这些。
另一个缺点就是,c风格的转换不容易查找,它由一个括号加上一个标识符组成,而这样的东西在c++程序里一大堆。c++为了克服这些缺点,引进了4个新的类型转换操作符,他们是static_cast,const_cast,dynamic_cast,reinterpret_cast.
static_cast
最常用的类型转换符,在正常状况下的类型转换, 用于将一种数据类型转换成另一种数据类型,如把int转换为float
使用形式
目标类型 转换后的变量 = static_cast<目标类型>(要转换的变量)
好处:不允许非法的转换发生;方便查找
int iNumber = 100;
float fNumber = 0;
fNumber = (float) iNumber;//C风格
fNumber = static_cast<float>(iNumber);
也可以完成指针之间的转换,例如可以将void*指针转换成其他类型的指针
void * pVoid = malloc(sizeof(int));
int * pInt = static_cast<int*>(pVoid);
*pInt = 1;
但不能完成任意两个指针类型间的转换
int iNumber = 1;
int * pInt = &iNumber;
float * pFloat = static_cast<float *>(pInt);//error
总结,static_cast的用法主要有以下几种:
1)用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性需要开发人员来保证;
2)把void指针转换成目标类型的指针,但不安全;
3)把任何类型的表达式转换成void类型;
4)用于类层次结构中基类和子类之间指针或引用的转换(后面学)。
const_cast
该运算符用来修改类型的const属性,基本不用。
常量指针被转化成非常量指针,并且仍然指向原来的对象;
常量引用被转换成非常量引用,并且仍然指向原来的对象;
常量对象被转换成非常量对象。
const int number = 100;
int * pInt = &number;//error 数据类型不同
int * pInt2 = const_cast<int *>(&number); // 转化后数据类型相同
dynamic_cast:该运算符主要用于基类和派生类间的转换,尤其是向下转型的用法中(后面讲)
reinterpret_cast
功能强大,慎用(也称为万能转换)
该运算符可以用来处理无关类型之间的转换,即用在任意指针(或引用)类型之间的转换,以及指针与足够大的整数类型之间的转换。由此可以看出,reinterpret_cast的效果很强大,但错误的使用reinterpret_cast很容易导致程序的不安全,只有将转换后的类型值转换回到其原始类型,这样才是正确使用reinterpret_cast方式。
dynamic_cast
该运算符主要用于基类和派生类间的转换,尤其是向下转型的用法中(后面讲)
const关键字
修饰内置类型*
const int number1 = 10;
int const number2 = 20;
const int val;//error 常量必须要进行初始化
const修饰的变量称为常量,之后不能修改其值
char/short/int/long/float/double 整型、浮点型数据都可以修饰——const常量
除了这种方式可以创建常量外,还可以使用宏定义的方式创建常量
#define NUMBER 1024
由此引出一个面试常考题:
const常量和宏定义常量的区别
-
发生的时机不同:C语言中的宏定义发生时机在预处理时,做字符串的替换;
const常量是在编译时(const常量本质还是一个变量,只是用const关键字限定之后,赋予只读属性,使用时依然是以变量的形式去使用)
-
类型和安全检查不同:宏定义没有类型,不做任何类型检查;const常量有具体的类型,在编译期会执行类型检查。
在使用中,应尽量以const替换宏定义,可以减小犯错误的概率。
修饰指针类型*
三种形式:const int * p int const * p1 int * const p2
int number1 = 10;
int number2 = 20;
const int * p1 = &number1;//常量指针
*p1 = 100;//error 通过p1指针无法修改其所指内容的值
p1 = &numbers;//ok 可以改变p1指针的指向
int const * p2 = &number1; //常量指针的第二种写法
int * const p3 = &number1;//指针常量
*p3 = 100;//ok 通过p3指针可以修改其所指内容的值
p3 = &number2;//error 不可以改变p1指针的指向
const int * const p4 = &number1;//两者皆不能进行修改
// const 左定值,右定向
// const 在*号的左面 ,就是指针指向的是一个定值
const int * p1 = &number1;//常量指针
*p1 = 100;//error 通过p1指针无法修改其所指内容的值
p1 = &numbers;//ok 可以改变p1指针的指向
// const 在*号的右面,就是指针的指向不能变是一个定向指针
int * const p3 = &number1;//指针常量
*p3 = 100;//ok 通过p3指针可以修改其所指内容的值
p3 = &number2;//error 不可以改变p1指针的指向
const int * const p4 = &number1;//两者皆不能进行修改
// 左定值的本质是值不变,只读,可以理解为将一个权限大的a(可读可写)的权限缩小了,且权限只能缩小不能增大
int a = 1;
int const *p = a;
// *p = 2; // error
a = 2; //right
//权限放大的例子
//int & p2 = 1;
// 1是const的对象,左面为可读可写权限放大了,普通对象可读可写
理解常量指针和指针常量的区别(重点)
类比
与这组概念相似的,再补充两组对比,也应该理解其含义,尝试写代码,分辨一下: