c++隐式类型转换及c风格类型转换的问题

前言:

上次的多线程系列因为某些原因暂时停了,后续会根据实际遇到的问题做一些补充。写博客是为了记录我遇到的问题以及解决,便于自我总结,也帮助遇到这些问题的人。
言归正传,本文介绍了c++以及c风格的强制类型转换的一些注意点。

一、c风格强制类型转换

  1. 问题描述: 我在做报文解析的时候遇到这个问题:
float x=32.128f;
float tmp=x*1000;
unsigned int ret=(unsigned int)tmp; //不安全转换,不推荐

这个看起来没啥问题,我当时预测是32128,但最后控制效果是32127,损失了一些精度。
2. 先说结论: 这得说到浮点数在内存中的存储,科学计数法,
符号位 + 1.XXXXXX(xxx是数据位)*2^ooooooo(o是指数位)
也就是说,float x=32.128f实际上在内存中以科学计数法表示,只能做到尽可能近似,而不会完全相等。
此处的x实际值可能是32.1279971当x*1000之后,值为32127.9971,然后强制转化为unsigned int ,暴力的把小数点后面给干掉了,导致结果为321227
3. 解决方法:
~避免使用这种类型转换,它是不安全的。
~如果一定要使用的话,请使用double,原因如下
double x=32.218;
实际上x=32.1280000000000000000012
简而言之,就是double的数据位数更多,可以更准确的表达x的值,从而减少运算造成的精度损失
4. 顺带一提:
~double等类型数据是否为0的判断:

double x;
if((x-0)<1e-10) //也是科学计数法的存储只能很接近原始数据的原因

~不同的机器对float的精度不一样,我用自己的电脑复现那个问题,需要把x*1000000,(可能我的精度比较高吧)

二、c++隐式转换问题浅谈

关于c++强制类型转换问题,主要对static_cast<>,看一段代码:代码中有注释不同类型,可根据需要选择浏览

#include<iostream>
using std::cout;
using std::endl;

class Parent
{
public:
 Parent(int x=0) :data_p(x) {} //构造
 void show()
 {
  cout << "parent: data_p=" << data_p << endl;
 }
protected:
 int data_p;
};

class Son :public Parent
{
public:
 Son(int ag = 0, int data = 0) :Parent(data), age(ag) {}
 void show()
 {
  cout << "son: adrs_age="<<&age << endl;
  cout << "son: adrs_data_p="<<&data_p << endl;
 }
private:
 int age;
};

class A	//测试int转class的类
{
private:
 int data;
 double s;
public:
 A(int d) :data(d) { s = 12.3; cout << "A() with one parameter" << endl; } //前面加explicit可避免此情况
 A(int d,double ss) :data(d),s(ss) {  cout << "A()with two parameters" << endl; }
 A(const A& t) :data(t.data),s(t.s) { cout <<" A(const A&t)" << endl; }
 void show()
 {
  cout << "A: data="<<data << endl;
  cout << "A: s=" << s<< endl;
 }
};


int main()
{
//1.基本数据类型之间的转换(int double 之类的),就不说啦。

//2.基类子类之间的转换
 //2.1对象转换
 Parent p;
 Son  s;
 cout << sizeof(s) << endl;    //转换前后,字节一样 
 s.show();        //转换前后,数据没被截断
 Parent  tmp1 = static_cast<Parent>(s); //把子类转换成基类
 cout << sizeof(s) << endl;
 s.show();
 //Son  tmp2 = static_cast<Son>(p); //禁止基类向子类转换
 cout << "我是分界线-------------------------------->" << endl;
 
 //2.2指针转换
 Parent *pp =new Parent;
 Son  *ps =new Son;
 Parent* tmp3 = static_cast<Parent*>(ps);//子类指针转为基类
 tmp3->show();
 //Son* tmp4 = static_cast<Son>(pp); //禁止基类向子类转换
 delete pp;
 delete ps;
 
cout << "我是分界线---------------------------->" << endl;
//3.隐式转换,例如从int转换为class ,或者struct
int a_data = 23;
 A a = static_cast<A>(a_data);  //int转换为类A,调用一个参数的构造函数
 a.show();
 
return 0;
}
  1. 基本数据类型转换:
  2. 子类和基类之间的转换:子类指针可以转基类指针,基类不能转子类(用dynamic_cast可以,但是转换后,子类的部分数据未知,不可控)。子类对象转基类是可以的,但是一般使用指针。总结,向上转换安全。
  3. 如果类的构造函数的参数只有一个变量(常量字符串不算),那么就会发生类似int--------->calss的隐式转换,要避免这种转换,可以再构造函数前面申明explicit
  4. 结构体我再Ubuntu上测试也是可以转换
    运行结果图如下:
    在这里插入图片描述

结语:

关于c++4种类型转换的使用,不在说啦,如有错误,欢迎指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值