【c++中的四种类型转换,应用场景】

c++中的四种类型转换

1.静态转换 : static_cast

用法:static_cast<type_name>(val)
1.基本类型间的转换
enum Day { Mon = 1, Tues = 2, Wed = 3, Thu = 4, Fir = 5, Sat = 6, Sun = 7 };

int main()
{
 int a = 10;
 char ch = 't';
 double dx = 21.65;
 a = static_cast<int>(ch);
 a = static_cast<int>(dx);
 Day x = Mon;
 a = x;
 x = static_cast<Day>(a);
 return 0;
}

2.指针转换
 int main()
 {
    int a = 10;
    char b = 'a';
    int* pa = &a;
    char* pb = &b;
    const int* pc = &a;
    pa = (int*)pb;  //c语言的强转,不安全
    pa = static_cast<int*>(pb);//error  类型不符合
     
    pa = (int*)pc; //c语言的强转,不安全
    pa = static_cast<int*>(pc);//error  无法去除const属性 
    return 0;
 }

总结:

1.不可以改变指针类型(特例:void型)

2.无法去除指针的const属性

3.对于void类型的指针,可以进行类型转换(如下)

int main()
{
 int a = 10;
 int* ip = nullptr;
 double* dp = nullptr;
 void* vp = &a;
 ip = static_cast<int*>(vp);
 dp = static_cast<double*>(vp);
 return 0;
}
3.左值到右值转换
int main()
{

    int a = 10;
    int &x = a;
    int &&rx = a; // error;
    int &&rx = static_cast<int &&>(a); 
    return 0;
}
4.自定义类型间的转换
class  Base
{
private:
    int  a;
public:
    Base(int x = 0) : a(x){}
};
class Obj : public Base
{
private:
	int val;
public:
	Obj(int x = 1) : val(x){}
};
class Int
{
    int val;
public:
    Int(int x = 2) : val(x){}
};
1. 不同类型间转换
int main()
{
    Base a;
    Int  b;
    Base* pa = &a;
    Int* pb = nullptr;
    pb = (Int*)pa; //c语言的强转,不安全
    pb = static_cast<Int*> (pa); //error  类型不一样
    
    return 0;
}

和内置类型一样,不行

2.上行转换
int main()
{
    Base a;
    Obj  b;
    Base* pa = &a;
    Obj* pb = &b;
    pa = pb; //隐式转换,(赋值兼容规则)
    pa = static_cast<Base*>(pb);
    
    a = b;   //隐式转换,(赋值兼容规则)
    a = static_cast<Base>(b);
    return 0;
}

注意:

隐式执行任何类型转换都可由static_cast显示完成。

static_cast不能转换掉val的const属性。

3.下行转换
int main()
{
    Base a;
    Obj  b;
    Base* pa = &a;
    Obj* pb = &b;
    pb = pa; //error ,不满足赋值兼容规则
    pb = static_cast<Obj*>(pa);
       //  pb->val 为随机值
    return 0;
}
会发生越界问题

2.去除常性转换 const_cast

用法:const_cast <type_name>(val)
特点:

1) 用于去除变量的只读属性

2) 强制转换的目标类型必须是指针或引用

1.内置类型
int main()
{
    const int a = 22; 
    const int* pb = &a;
    const int& b = a;
 
    int* pc = const_cast<int*> (pb);
    *pc  = 100;
    cout<<"a = "<<a<<" *pc = "<<*pc<<endl;
    int& la = const_cast<int&> (b);
    cout<<"a = "<<a<<" la = "<<la<<endl;
    int&& ra = const_cast<int&&> (b); 
    cout<<"b = "<<b<<"ra = "<<endl;
    return 0;
}

运行结果:

出现这种情况是因为 源程序 形成 可执行程序时需要经历4个步骤,分别是 预编译 , 编译 ,汇编, 链接 ;

其中 预编译阶段

a) 删除所有的“#define”,并且展开所有的宏定义;所有的const内置类型在预编译阶段就已经做了类似于宏替换的工作

b) 处理所有的条件预编译指令,“#if”、“#ifdef”、“#endif”等;

c) 处理“#include”预编译指令,将被包含的文件插入到该预编译指令的位置;

d) 删除所有的注释;

e) 添加行号和文件名标识,以便于编译器产生调试用的符号信息及编译时产生编译错 误和警告时显示行号;

f) 保留所有的#pragma 编译器指令,因为编译器需要使用它们。

2.自定义类型
class Int
{
    int value;
public:
    Int(int x = 0) : value(x) {}
    ~Int() {}
    void SetValue(int x) { value = x; }
    int GetValue() const { return value; }
};

int main()
{
    const Int a(10);
    cout <<"a: " << a.GetValue() << endl;
    Int *ip = const_cast<Int *>(&a);
    Int &b = const_cast<Int &>(a);
    ip->SetValue(100);
    cout <<"a : " << a.GetValue() << endl;
    b.SetValue(200);
    cout <<"a : " << a.GetValue() << endl;
    system("pause");
}

运行结果:

结论:

  1. 对于自定义类型常量,不会进行类似宏替换操作。
  2. 常量指针被转化成非常量的指针,并且仍然指向原来的对象;
  3. 常量引用被转换成非常量的引用,并且仍然引用原来的对象;

3. 重新解释转换 reinterpret_cast

用法:reinterpret_cast<type_name> (val)
说明:

type_name必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换
成一个整数,也可以把一个整数转换成一个指针。类似C语言的强转。

用途:
1.用于指针类型间的强制转换 (无法去除const)
  1. 基本类型
int main()
{
 int a = 0x61626364; // a b c d

 char* p = reinterpret_cast<char*>(&a);
 cout << *p << endl;
 p += 1;
 cout << *p << endl;
 p += 1;
 cout << *p << endl;
 p += 1;
 cout << *p << endl; 
}

内存分布图:

运行结果:

  1. 自定义类型
class Object
{
private:
 int value;
public:
Object(int x = 0) :value(x) {}
 ~Object() {}
 int& Value() { return value; }
 const int& Value() const { return value; }
};

int main()
{
 Object obj(10);
 int* p = reinterpret_cast<int*>(&obj);
 int& a = reinterpret_cast<int&>(obj);
 cout << obj.Value() << endl;
 *p = 100;
 cout << obj.Value() << endl;
 a += 100;
 cout << obj.Value() << endl;
 return 0;
}

运行结果:

注:对于自定义的类型尽量不要进行此类转换,如虚基类(含有虚基类指针),有函数虚函数的类(含有虚表指针),它们的地址空间中的成员信息分布计算容易出错,导致错误访问。

2.用于整数和指针类型间的强制转换
void fun(void* p)
{
    int a = reinterpret_cast<int>(p);  //指针到整数
    cout<<a<<endl;
}
int main()
{
    int a = 100;
    fun(reinterpret_cast<void*>(a)); //整数到指针
    
    return 0;
}

运行结果:

4.动态转换 dynamic_cast

原理:RTTI

博客链接:点击跳转(建议先了解)

用法: dynamic_cast<type_name> (val)
说明:必须是公有继承,基类要有虚函数。

允许在运行时刻进行类型转换 ,从而使程序能够在一个类层次结构中安全地转换类型, 把基类指针转换成派生类指针,或把指向基类的左值转换成派生类的引用。

type_name 只能是自定义类型的指针或引用。

特点:
  1. 与C++支持的其他强制转换不同的是, dynamic_cast 是在运行时执行的类型转换。
  2. 如果针对指针类型的 dynamic_cast 失败, 则dynamic_cast 的结果是 nullptr。
  3. 如果针对引用类型的 dynamic_cast 失败, 则 dynamic_cast 会抛出一个异常。
  4. 在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的。
  5. 在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。

我们主要来看下行转换

class Object
{
private:
 int value;
public:
 Object(int x = 0) :value(x) {}
 virtual void func() { cout << "value: " << value << endl; }
};
class Base : public Object
{
private:
 int num;
public:
 Base(int x = 0) :Object(x + 10), num(x) {}
 void func() { cout << "num: " << num << endl; }
};

1.正确的下行转换

int main()
{
 Base base;
 Object* pobj = &base;  
 Base* pa = dynamic_cast<Base*>(pobj); //动态转换
}

图解:


运行时检查

2.错误的下行转换

int main()
{
 Base base;
 Object* pobj = nullptr;
 Object obj;
 pobj = &obj;
 Base* pa = dynamic_cast<Base*>(pobj); // 动态转换   pa = nullptr
 if(pa == nullptr) {cout << "hello world!" << endl;}
 Base* pb = static_cast<Base*>(pobj);  //不安全
}

图解:


运行时检查

运行结果:

3.引用

int main()
{
	Base base(22); 
	Object obja(11);
	Object& obj = obja;
	try 
	{
		Base& a = dynamic_cast<Base&>(obj); // 动态转换 
		a.func();
	}
	catch (std::bad_cast& e)
	{
		cout << e.what()<<endl;
	}

	Object& obj1 = base;
	Base& b = dynamic_cast<Base&>(obj1); // 动态转换 
	b.func();
}

图解:

运行结果:

结论:

使用异常给程序增加了相应的运行开销 ,所以dynamic_cast尽可能使用指针。

  1. 和void型指针结合问题
int main()
{
    Base b;
    Object& obj = b;
    void* pobj = &obj;  //正确,void型指针可以指向任意类型
    Base* pb = dynamic_cast<Base*> (pobj);  //error,pobj的类型是void(无类型信息)
}

结论:

dynamic_cast 的操作数必须是指向完整类型的指针。

  • 47
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值