前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++11类型转换

C++11类型转换

作者头像
芝士就是菜
发布2023-04-20 19:16:36
3480
发布2023-04-20 19:16:36
举报
文章被收录于专栏:芝士就是菜芝士就是菜

C语言中的类型转换

隐式类型转换

隐式类型转换(意义相近的类型)

代码语言:javascript
复制
int i = 1;
// 隐式类型转换(意义相近的类型)
double d = i;
printf("%d, %.2f\n", i, d);

显示类型转换

显示的强制类型转换(意义不相近的类型,值转换后有意义)

代码语言:javascript
复制
int main()
{
 int a = 1;
 int* p = &a;

 //int address = p; //这样没法隐式类型转换会报错
 int address = (int)p; //强制类型转换没问题

 printf("%x, %d\n", p, address);
}

C++强制类型转换

c++也支持c的类型转换,但是c++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符

static_cast

这个就像c中的隐式类型转换,只不过显示的写了出来,static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast,但它不能用于两个不相关的类型进行转换

代码语言:javascript
复制
int main()
{
 double d = 12.34;
 int a = static_cast<int>(d);
 cout << a << endl;
 return 0;
}

reinterpret_cast

类似于c的显示强制类型的转换,一般用于将一种类型转换为另一种不同的类型

代码语言:javascript
复制
int main()
{
 int a = 10;
 int* p = reinterpret_cast<int*>(a);  // 把int 强转为 int*
 return 0;
}

const_cast

能够删除变量的const属性

代码语言:javascript
复制
int main()
{
 const int a = 2;
 //int* p = const_cast<int*>(&a);
 int* p = (int*)&a; // c的那一套也可以
 *p = 3;
 cout << a << endl;
 cout << *p << endl;

 return 0;
}

但是上边的代码会出现一个问题,就是运行结果显示,a还是2,不过当我们打开监视窗口可以看到a其实已经被改成3了,这是什么原因呢?

代码语言:javascript
复制
a被const修饰,编译器以为不会被修改,所以加载到寄存器,虽然内存中已经被改了但是寄存器里面的还是2,cout的时候直接去寄存器读,所以打印出来是2

我们可以在定义a变量的时候加上 volatile关键字,这样编译器处理的时候就会去内存中读取数据,这样,运行结果就变成3 3了。

注:

  1. 兼容c隐式类型转换和强制类型转换
  2. 期望不要再用了,最好用规范的cpp显示强制类型转换
  3. static_cast(隐式类型转换)、reinterpret_cast、const_cast(强制类型转换)

dynamic_cast

用于将一个父类对象的指针或者引用转换为子类的指针或者引用(动态转换)

向上转型:子类对象指针/引用->父类指针/引用 (不需要转换,赋值兼容规则)向下转型:父类对象指针/引用->子类指针/引用 (用dynamic_cast转型是安全的)

  1. dynamic_cast只能用于父类含有虚函数的类
  2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0
代码语言:javascript
复制
class A
{
public:
 virtual void f(){}
public:
 int _a = 0;
};

class B : public A
{
public:
 int _b = 1;
};

// A*指针pa有可能指向父类,有可能指向子类
void fun(A* pa)
{
 // 如果pa是指向子类,那么可以转换,转换表达式返回正确的地址
 // 如果pa是指向父类,那么不能转换,转换表达式返回nullptr
 B* pb = dynamic_cast<B*>(pa); // 安全的
 //B* pb = (B*)pa;             // 不安全
 if (pb)
 {
  cout << "转换成功" << endl;
  pb->_a++;
  pb->_b++;
  cout << pb->_a << ":" << pb->_b << endl;
 }
 else
 {
  cout << "转换失败" << endl;
  pa->_a++;
  cout << pa->_a << endl;
 }
}

int main()
{
 A aa;
 // 父类对象无论如何都是不允许转换成子类对象的
 /*B bb = dynamic_cast<B>(aa);
 B bb = (B)aa;*/
 B bb;

 fun(&aa);
 fun(&bb);
 //fun(nullptr); 转换失败并且报错

 return 0;
}

细节部分:

代码语言:javascript
复制
class A1
{
public:
 virtual void f(){}
public:
 int _a1 = 0;
};

class A2
{
public:
 virtual void f(){}
public:
 int _a2 = 0;
};

class B : public A1, public A2
{
public:
 int _b = 1;
};

int main()
{
 B bb; //定义子类对象
 A1* ptr1 = &bb;
 A2* ptr2 = &bb;
 cout << ptr1 << endl;
 cout << ptr2 << endl << endl;  //这两个地址是不同的

 B* pb1 = (B*)ptr1;
 B* pb2 = (B*)ptr2;
 cout << pb1 << endl;
 cout << pb2 << endl << endl;

 B* pb3 = dynamic_cast<B*>(ptr1);
 B* pb4 = dynamic_cast<B*>(ptr2);
 cout << pb3 << endl;
 cout << pb4 << endl << endl;

 return 0;
}
代码语言:javascript
复制
可以看到,强转成子类指针,和dynamic_cast都可以将指针位置偏移到头上

总结:

  • 如果有个子类的对象,将地址传给一个函数,函数形参是父类的指针,那么函数内部可以将这个指针重新安全的转成子类的指针。
  • 普通的父类指针强转成子类可能有风险,如果父类的指针本来指向的对象就是父类的对象,那么将这个指针转换成子类,会有越界的风险。

RTTI

Run-time Type identification :运行时类型识别

c++通过以下方式支持RTTI

  1. typeid运算符 (获取对象类型的字符串)
  2. dynamic_cast运算符 (识别父类的指针是指向父类对象还是子类对象)
  3. decltype (推导一个对象类型,这个类型可以用来定义另一个对象)
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-02-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 芝士就是菜 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • C语言中的类型转换
    • 隐式类型转换
      • 显示类型转换
      • C++强制类型转换
        • static_cast
          • reinterpret_cast
            • const_cast
              • dynamic_cast
              • RTTI
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档