类型转换即将一种数据类型转换称另外一种数据类型,C中有隐式转换和强制转换,其中强制转换使用同一转换格式去处理任意类型间的转换,而C++做为C的超集,在支持C的类型转换功能上,在强制转换上细分出四种类型转换操作符来进行强制转换,分别是static_cast, dynamic_cast, reinterpret_cast, 与const_cast。
一、C中的类型转换
1.1 隐式转换
即自动转换,由C编译器自动执行,无需程序员干预。 1 表达式中地类型提升: 表达式中如果包含几种不同地数据类型,表达式类型为当前表达式中最高类型; 比如 x+y, 一个是int,一个是float,则表达式类型为float
2 赋值时地类型转换 当赋值时两边地类型不同时,赋值运算符右边地表达式会被提升(降级)为左边数据对象地类型,即右边地数据地数据类似会被强制变成左边地数据类型,但是并不改变赋值右边原对象。
隐式转换提升有如下规则:原则尽量保持精度,即低精度(float)会向高精度(double)转换,存储空间小(char)会向空间大类型转换(int)。
1.1强制转换
强制类型转换使用强制转换运算符在程序中手动地对类型转换进行控制,强制转换由表达式和其前面用圆括号括起来地类型组成,对算术表达式和指针都可以执行强制类型转换。强制转换可以进行任意任性转换(比如除了基本类型转换,还可以用于指针转换,const指针/引用-》非const指针/引用,继承类之间转换) 1 强制转换算法表达式地类 如将float b 转换为int a : a=(int) b; 2 强制转换指针地类型 以void为例: 注意,给void指针赋值或将其与NULL作比较时,不需要执行强制类型转换,但是对其解引用或执行指针运算之前必须转成合适地类型。 int* a=(int*)malloc(size0f(int)); //malloc函数返回地是void类型指针,强制强制转换为int*;
二、C++中的类型转换
1 C++对C中类型转换的原因:
补充:C++与C地显示转换的区别 1 容易辨识:尖括号<>使得C++类型转换操作符非常容易辨识,而在编程中我们也可以搜索“_cast”来寻找类型转换,C风格的类型转换语法显然更容易被忽略,从而导致出错。 2 语义明确,C++的几种类型转换操作符语义都互不相同,而C风格的类型转换都是用一个相同的语法代替,没有进行区分,比如你可以把一个指向 const 对象的指针转换 成指向非 const 对象的指针,把一个指向基类对象的指针转换成指向一个派生类对象的 指针,这两种转换之间的差别是巨大的,但是传统的 c 语言风格的类型转换没有区分这些。并且一般类型reinterpret_cast并不能用C风格的类型转换实现(只有涉及指针的时候才可以),
2 C++中隐式转换规则:
规则总结:(同C) -》非浮点类型从短类型到长类型 -》非浮点类型转换为浮点类型 -》低精度浮点类型转换为高精度浮点类型 -》signed类型转换到unsigned类型
3 C++中显示转换规则:
类型转换操作符 | 说明 |
---|
static_cast | 静态类型转换 | dynamic_cast | 父子类之间的多态类型转换 | const_cast | 去掉const属性 | reinterpret_cast | 重新解释类型转换 |
static_cast: (静态转换,在编译期间转换) (1)主要用于内置数据类型之间的相互转换,
float floatnum=1.2;
int intnum=static_cast<int>(floatnum);
(2)也可以转换自定义类型。如果涉及到类,static_cast只能在有相互联系(继承)的类型间进行转换,且不一定包含虚函数。
class A{
};
class B : public A{
};
class C{
};
void main()
{
A *pA = new A;
B *pB = static_cast<B*>(pA);
pB = new B;
pA = static_cast<A*>(pB);
C *pC = static_cast<C*>(pA);
}
(3)把void类型指针转换成目标类型的指针(不安全)
dynamic_cast: 用于在类的继承层次之间进行类型转换,它既允许向上转型(Upcasting),也允许向下转型(Downcasting)。向上转型是无条件的,不会进行任何检测,所以都能成功;向下转型的前提必须是安全的,要借助 RTTI 进行检测,所有只有一部分能成功。(会在程序运行期间借助 RTTI 进行类型转换,这就要求基类必须包含虚函数) (newType 和 expression 必须同时是指针类型或者引用类型。换句话说,dynamic_cast 只能转换指针类型和引用类型,其它类型(int、double、数组、类、结构体等)都不行。) (1)其他三种都是编译时完成的。dynamic_cast是运行时处理的,运行时要进行类型检查。 (2)不能用于内置基本数据类型间的强制转换。例如:
double dValue = 12.12;
int nDValue = dynamic_cast<int>(dValue);
(3)使用dynamic_cast进行转换时,基类中一定要有虚函数,否则编译不通过。 需要有虚函数的原因:类中存在虚函数,就说明它有想要让基类指针或引用指向派生类对象的必要,此时转换才有意义。 由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表中,只有定义了虚函数的类才有虚函数表。 (4)dynamic_cast转换若成功,返回的是指向类的指针或引用;若失败则会返回NULL。 (5)在类的转换时,在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的。 在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。 向上转换即为指向子类对象的向上转换,即将子类指针转化父类指针。 向下转换的成败取决于将要转换的类型,即要强制转换的指针所指向的对象实际类型与将要转换后的类型一定要相同,否则转换失败。
#include<iostream>
class Animal {
public:
virtual void cry() = 0;
};
class Dog : public Animal
{
public:
virtual void cry()
{
std::cout << "旺旺" << std::endl;
}
void dohome()
{
std::cout << "看家" << std::endl;
}
};
class Cat : public Animal
{
public:
virtual void cry()
{
std::cout << "喵喵" << std::endl;
}
void dohome()
{
std::cout << "抓老鼠" << std::endl;
}
};
int main()
{
Animal* base = NULL;
base = new Cat();
base->cry();
Dog *pDog = dynamic_cast<Dog*>(base);
if (pDog != NULL)
{
pDog->cry();
pDog->dohome();
}
Cat* pCat = dynamic_cast<Cat*>(base);
if (pCat != NULL)
{
pCat->cry();
pCat->dohome();
}
system("pause");
return 0;
}
const_cast:
const_cast的作用:const_cast 目标类型只能是引用或者指针 一、常量指针 被强转为 非常量指针,且仍然指向原来的对象; 二、常量引用 被强转为 非常量引用,且仍然指向原来的对象; 三、常量对象 被强转为 非常量对象。
reinterpret_cast:
有着与C风格的强制转换同样的能力。 它可以转化任何内置的数据类型为其他任何的数据类型,也可以转化任何指针类型为其他的类型。 它甚至可以转化内置的数据类型为指针,无须考虑类型安全或者常量的情形。不到万不得已绝对不用。 reinterpret_cast可以做任何类型的转换,不过不对转换结果保证,容易出问题。 注意:为什么不用C的强制转换:C的强制转换表面上看起来功能强大什么都能转,但是转换不够明确,不能进行错误检查,容易出错。
|