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

c++中的四种类型转换

1.静态转换 : static_cast

用法:static_cast<type_name>(val)
1.基本类型间的转换
c++ 复制代码
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.指针转换
c++ 复制代码
 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类型的指针,可以进行类型转换(如下)

c++ 复制代码
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.左值到右值转换
c++ 复制代码
int main()
{

    int a = 10;
    int &x = a;
    int &&rx = a; // error;
    int &&rx = static_cast<int &&>(a); 
    return 0;
}
4.自定义类型间的转换
c++ 复制代码
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. 不同类型间转换
c++ 复制代码
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.上行转换
C++ 复制代码
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.下行转换
c++ 复制代码
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.内置类型
C++ 复制代码
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.自定义类型
c++ 复制代码
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

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

type_name必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换

成一个整数,也可以把一个整数转换成一个指针。类似C语言的强转。

用途:
1.用于指针类型间的强制转换 (无法去除const)
  1. 基本类型
c++ 复制代码
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. 自定义类型
c++ 复制代码
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.用于整数和指针类型间的强制转换
c++ 复制代码
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更安全。

我们主要来看下行转换

c++ 复制代码
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.正确的下行转换

c++ 复制代码
int main()
{
 Base base;
 Object* pobj = &base;  
 Base* pa = dynamic_cast<Base*>(pobj); //动态转换
}

图解:

运行时检查

2.错误的下行转换

c++ 复制代码
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.引用

c++ 复制代码
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型指针结合问题
c++ 复制代码
int main()
{
    Base b;
    Object& obj = b;
    void* pobj = &obj;  //正确,void型指针可以指向任意类型
    Base* pb = dynamic_cast<Base*> (pobj);  //error,pobj的类型是void(无类型信息)
}

结论:

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

相关推荐
捕鲸叉4 小时前
怎样在软件设计中选择使用GOF设计模式
c++·设计模式
捕鲸叉4 小时前
C++设计模式和编程框架两种设计元素的比较与相互关系
开发语言·c++·设计模式
未知陨落5 小时前
数据结构——二叉搜索树
开发语言·数据结构·c++·二叉搜索树
一丝晨光6 小时前
gcc 1.c和g++ 1.c编译阶段有什么区别?如何知道g++编译默认会定义_GNU_SOURCE?
c语言·开发语言·c++·gnu·clang·gcc·g++
汉克老师6 小时前
GESP4级考试语法知识(贪心算法(四))
开发语言·c++·算法·贪心算法·图论·1024程序员节
姆路7 小时前
QT中使用图表之QChart绘制动态折线图
c++·qt
秋说8 小时前
【数据结构 | C++】整型关键字的平方探测法散列
数据结构·c++·算法
槿花Hibiscus10 小时前
C++基础:Pimpl设计模式的实现
c++·设计模式
黑不拉几的小白兔11 小时前
PTA部分题目C++重练
开发语言·c++·算法
写bug的小屁孩11 小时前
websocket身份验证
开发语言·网络·c++·qt·websocket·网络协议·qt6.3