c++怎么转换类型,C++四种类型转换
说到阅读指南类型转换,相信有过编程经验的朋友都不陌生。之前,作者在论文《NDK编程Java如何保存C或C++对象》中使用了强类型变换的方法。
既然C是继承了C的语言,那么在类型转换上做了哪些扩展?
c语言转换
C语言的类型转换很简单,一个括号就可以完成强转换:(Type)var;C语言转换虽然简单,但是缺点很多,比如可以在任意类型之间转换,比如将const类型的对象转换为非const类型的对象,
你可以把基类的对象指针转换成派生类的对象指针,等等。这些强制转换对C来说显然是不合理的,为了克服这些缺点,C引入了四种新的类型转换运算符,它们是静态类型转换、动态类型转换、常量类型转换和重解析类型转换。
c语言的类型转换
1.静态类型转换
静态类型转换使用static_cast,可用于强制隐式转换,如将非const对象转换为const对象,将int转换为double等。
也可以用于很多此类转换的反向转换,比如void*指针转换为类型化指针,基类指针转换为派生类指针等。
所谓静态类型,就是编译器可以确定的类型。静态类型转换的格式是:
Static_cast目标类型(标识符)
例如:
int main() {
双圆周率=3.1415926;
int a=(int)pi;//C语言的旧式类型转换
int b=pi//隐式类型转换
int c=static _ cast int(pi);//c的新类型转换运算符
返回0;
}
2.动态类型转换
与静态类型转换相比,它是动态类型转换。动态类型是一种在编译过程中无法确定的类型,需要在运行时确定。它由dynamic_cast标识,其格式为
Dynamic_cast目标类型(标识符)
动态类型转换的一个重要作用是将父类对象转换为派生类对象,如果转换失败,将返回一个空指针。
示例:
主页面
动物类{
公共:
虚拟作废打印(){
STD:cout print print STD:endl;
虚拟~动物(){
类别猫:公共动物{
公共:
作废打印()覆盖{
STD:cout print Cat STD:endl;
狗类:公共动物{
作废打印()覆盖{
STD:cout print Dog STD:endl;
int main() {
animal * animal=new Cat();
狗*狗=dynamic_cast狗*(动物);//如果转换失败,将返回一个空指针
if(nullptr==dog){
Std:cout“转换失败”STD:endl;
Cat *cat=dynamic_cast Cat*(动物);
如果(猫){
Std:cout“转换成功”STD:endl;
返回0;
}
dynamic_cast的转换必须基于多态性,也就是说父类必须有虚函数或者纯虚函数,否则转换不会被编译。
公共:
int a;
Fruit():a(10){
//必须有虚函数或者纯虚函数,否则无法编译dynamic_cast转换。
虚拟void show();
苹果类:大众水果{
void show()覆盖{
void printApple(苹果*苹果){
int main() {
水果*苹果=新苹果();
//printApple(苹果);//错误,*苹果的类型是水果,但函数printApple需要一个苹果指针。
print Apple(dynamic _ cast Apple *(Apple));
返回0;
3.常量类型转换
常量类型转换也叫越轨转换,是指常量变量可以转换成非常量变量,使用的标识符是const_cast。
const_cast最常见的用途是去除对象的恒常性,它只能应用于指针或引用。
我们知道const对象只能调用const函数,那么如果const对象也想调用非const函数呢?这时候就需要用const_cast来出规范了。
让我们来看下面两个例子:
void func(int a){
STD:cout func-a: a STD:endl;
a=100//此处引用的值已被更改。行得通吗?你需要看看传递的变量是不是const的。
int main() {
const int d=30
func(const _ cast int(d));//如果在func中修改d的值,可以吗?不可以
STD:cout d: d STD:endl;
返回0;
}
水果类{
公共:
int a;
Fruit():a(10){
无效打印(水果水果){
水果.=20
Std:cout 水果地址:水果STD:endl;
int main() {
果果;
const Fruit constFruit=水果;
STD:cout a: fruit . a STD:endl;
Std:cout constFruit地址: const fruit STD:endl;
constFruit.a=20//错误,无法修改变量A
print(const fruit);//错误,不能将由const修改的变量传递给不由const修改的函数。
print(const_cast水果(const Fruit));//可以,通过const_cast类型转换,并且可以在函数内部修改constFruit的变量A。
STD:cout const fruit . a: const fruit . a STD:endl;
返回0;
}
上面两个例子中,为什么一个类被const_cast转换后,在函数内部修改了该类的成员变量,但const_cast转换后在函数内部修改了int类型的值,却不生效?
这里需要记住一个结论:
使用const_cast移除由const限定的属性的目的不是修改其内容,而是使函数能够接受这个实际参数。
因此,使用const_cast移除const定义属性的类对象可以改变成员变量,但对于内置数据类型,则表现出未定义的行为。
4、重新诠释_演员表
重新诠释_铸造.专门用于底层强制转换,该运算符的转换结果几乎总是与编译平台密切相关。也就是说,reinterpret_casts没有跨平台的可移植性,
所以这里就不多做介绍了。
5.隐式转换
隐式转换给我们带来便利的同时,也给我们带来了各种隐患。
我们通过下面的程序来简单看一下隐式转换带来的隐患:
命名空间传单{
A级
公共:
年龄(年龄){
Std:cout“自定义构造函数”endl
A(常数A a) {
Std:cout“复制构造”endl
~A() {
Std:cout“析构函数”endl
公共:
int age
int main() {
传单:A a=10//隐式转换初始化实际上调用了A的构造函数,这是不明确的。
a=30//调用的构造函数
返回0;
}
在上面的程序中,因为隐式转换的存在,可能是简单的赋值操作,却变成了类结构,给人一种欺骗我眼睛的感觉。
想去除隐式转换,彻底消除这样的隐患,应该怎么做?答案也很简单,就是给类的构造函数添加explicit关键字:
使用命名空间std
命名空间传单{
A级
公共:
explicit A(int age) : age(age) {
Std:cout“自定义构造函数”endl
A(常数A a) {
Std:cout“复制构造”endl
~A() {
Std:cout“析构函数”endl
公共:
int age
int main() {
传单:A a=10//错误,显式不运行隐式转换
传单:A b { 30 };//正确,调用构造函数
b=40//错误,显式不运行隐式转换
返回0;
}
需要转换,但又不想接受隐性转换的隐患怎么办?在《More Effective C++》这本书里,作者给了我们一些建议:
第21条:使用重载技术避免隐式类型转换
《C++之指针扫盲》
《C++之智能指针》
《C++之指针与引用》
《C++之右值引用》
关注我,共同进步,生活不止编码!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。