你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

C++——类型转换函数

[复制链接]
gaosmile 发布时间:2020-8-29 23:30

一、转换构造函数的学习:

1、回忆数据类型转换:

在平时写代码的时候,最怕的就是那种隐式数据类型转换了,一不小心,软件就bug不断;而显式数据类型(一般是程序自己去强制类型转换,这个是我们能够明显的识别和掌控的)。为此我们这里总结了一副隐式类型转换的图:

微信图片_20200829233028.png

下面我们来几个隐式转换的例子:

代码版本一:

#include <iostream>
#include <string>

int main()
{
     short s ='a';
     unsigned int ui = 100;
     int i = -200;
     double d = i;

     std::cout<<"d =" << d <<std::endl;
     std::cout<<"ui= "<<ui<<std::endl;

     if((ui+i)>0)
     {
          std::cout<<"ostive"<<std::endl;
     }
     else
     {
        std::cout<<"Negative"<<std::endl;
     }

     return 0;
}

输出结果:

root@txp-virtual-machine:/home/txp# ./a.out
d =-200
ui= 100
Postive

注解:这里我们明显发现(-200+100)还是大于0,这显然不符合正常人的思维了;所以我们仔细分析一下,发现这里肯定是进行了隐式转换了,为此我们再加一条语句看看(ui+i)的值到底是多少:

代码版本二:

#include <iostream>
#include <string>

int main()
{
     short s ='a';
     unsigned int ui = 100;
     int i = -200;
     double d = i;

     std::cout<<"d =" << d <<std::endl;
     std::cout<<"ui= "<<ui<<std::endl;

     if((ui+i)>0)
     {
        std::cout<<"(ui+i) = "<<ui+i<<std::endl;
        std::cout<<"ostive"<<std::endl;
     }
     else
     {
        std::cout<<"Negative"<<std::endl;
     }

     return 0;
}

输出结果:

root@txp-virtual-machine:/home/txp# ./a.out
d =-200
ui= 100
(ui+i) = 4294967196
Postive

注解:通过打印(ui+i)的值我们发现,i原本是int数据类型,这里隐式转换成无符号的数据类型了

为了让大家更加理解隐式的转换,我们下面再来一个例子:

代码版本三:

#include <iostream>
#include <string>

int main()
{
     short s ='a';
     unsigned int ui = 100;
     int i = -200;
     double d = i;

     std::cout<<"d =" << d <<std::endl;
     std::cout<<"ui= "<<ui<<std::endl;

     if((ui+i)>0)
     {
        std::cout<<"(ui+i) = "<<ui+i<<std::endl;
        std::cout<<"ostive"<<std::endl;
     }
     else
     {
        std::cout<<"Negative"<<std::endl;
     }

     std::cout<<"sizeof(s+'b') = "<<sizeof(s+'b')<<std::endl;

     return 0;
}

输出结果:

root@txp-virtual-machine:/home/txp# g++ test.cpp
root@txp-virtual-machine:/home/txp# ./a.out
d =-200
ui= 100
(ui+i) = 4294967196
Postive
sizeof(s+'b') = 4

注解:这里我们发现sizeof出来的内存大小是4个字节大小;其实这里编译器把short和char类型的都转换int类型了,所以最终两个int数据相加,所占的内存大小就是int类型了。

所以咋们平时在写代码的时候,脑袋里面要有这种写代码谨慎的思维,防止出现这种隐式转换的情况出现,养成写代码的好习惯

2、普通类型与类类型之间能否进行类型转换,类类型之间又是否能够类型转换呢?

为了说明这些问题,咋们通过实际的代码测试来看看啥情况:

代码:普通类型转换成类类型

#include <iostream>
#include <string>

class Test{

public:
    Test()
    {

    }
    Test(int i)
    {

    }
};

int main()
{
     Test t;

     t =6; 从 C 语言角度,这里将 5 强制类型转换到 Test 类型,只不过编译器 在这里做了隐式类型转换

     return 0;
}

输出结果(显示可以编译通过)

root@txp-virtual-machine:/home/txp# g++ test.cpp
root@txp-virtual-machine:/home/txp# ./a.out

代码类类型转换为普通类型

#include <iostream>
#include <string>

class Test{

public:
    Test()
    {

    }
    Test(int i)
    {

    }
};

int main()
{
     Test t;

     int i = t;

     return 0;
}

输出结果(没有编译通过)

root@txp-virtual-machine:/home/txp# g++ test.cpp
test.cpp: In function ‘int main()’:
test.cpp:21:14: error: cannot convert ‘Test’ to ‘int’ in initialization
      int i = t;
              ^

代码类类型与类类型之间的转换:

#include <iostream>
#include <string>

class Value{

};


class Test{

public:
    Test()
    {

    }
    Test(int i)
    {

    }
};

int main()
{
     Test t;
     Value i;

     t=i;

     return 0;
}

输出结果(暂时还是不行,编译不通过):

root@txp-virtual-machine:/home/txp# g++ test.cpp
test.cpp: In function ‘int main()’:
test.cpp:27:7: error: no match for ‘operator=’ (operand types are ‘Test’ and ‘Value’)
      t=i;
       ^
test.cpp:27:7: note: candidate is:
test.cpp:9:7: note: Test& Test:perator=(const Test&)
class Test{
       ^
test.cpp:9:7: note:   no known conversion for argument 1 from ‘Value’ to ‘const Test&’

说明:上面的例子,我们只是简单的按照实际角度出发,发现确实有写转换行不通。那么真理到底是怎样的?我们接着往下看

3、转换构造函数出厂:

我们前面学习过构造函数,构造函数它可以定义不同类型的参数;但是我们今天这里所说的转换构造函数的定义时这样的:

  • 有且仅有一个参数

  • 参数是基本类型

  • 参数是其它类型


接着我们对上面的普通数据类型转换类类型的代码进行分析:

#include <iostream>
#include <string>

class Test{

public:
    Test()
    {

    }
    Test(int i)
    {

    }
};

int main()
{
     Test t;

     t =6; //从 C 语言角度,这里将 5 强制类型转换到 Test 类型,只不过编译器 在这里做了隐式类型转换

     return 0;
}

分析:

上面的Test(int i )就是一个转换构造函数,所以我们上面的这句隐式转换语句:

t =6

这里其实发生了我们刚才说的利用了转换构造函数,把6转换成Test(6),而这样写就会产生一临时对象,所以就可以进行赋值了;但是在现在的技术发展中,肯定是不希望出现这种要人去防止这隐式转换,所以在c++中有了新技术来防止出现隐式转换:

  • 工程中通过explicit关键字杜绝编译器的转换尝试

  • 转换构造函数被explicit修饰只能进行显示转换(也就是强制类型转换)


代码实践一:

#include <iostream>
#include <string>

class Test{

public:
    Test()
    {

    }
   explicit Test(int i)
    {

    }
};

int main()
{
     Test t;

     t =6;

     return 0;
}

输出结果:

root@txp-virtual-machine:/home/txp# g++ test.cpp
test.cpp: In function ‘int main()’:
test.cpp:21:8: error: no match for ‘operator=’ (operand types are ‘Test’ and ‘int’)
      t =6;
        ^
test.cpp:21:8: note: candidate is:
test.cpp:4:7: note: Test& Test:perator=(const Test&)
class Test{
       ^
test.cpp:4:7: note:   no known conversion for argument 1 from ‘int’ to ‘const Test&’

注解:这里显示不能这样转换

代码实践二(进行显示转换):

#include <iostream>
#include <string>

class Test{

public:
    Test()
    {

    }
   explicit Test(int i)
    {

    }
};

int main()
{
     Test t;

     t =static_cast<Test>(6);
     return 0;
}

输出结果(编译通过):

root@txp-virtual-machine:/home/txp# g++ test.cpp
root@txp-virtual-machine:/home/txp#

4、小结:

  • 转换构造函数只有一个参数

  • 转换构造函数的参数类型是其它类型

  • 转换构造函数在类型转换时被调用

  • 隐式类型转换是工程中bug的重要来源

  • explicit关键字用于杜绝隐式类型转换


二、类型转换函数:

1、类类型转换普通类型:

在我们上面通过代码测试发现不行,那么是真的不行吗,事实是可以进行转换的,不过要用到我们现在c++里面的类型转换函数(它用于将类对象转换为其它类型),类型转换的语法如下:

operator Type()
{
    Type ret;
     
    return ret;

}

代码实践:

#include <iostream>
#include <string>

class Test{

public:
    Test()
    {

    }
   operator int()
   {

    }
};

int main()
{
     Test t;
     int i =t;

     return 0;
}

输出结果(编译没有报错):

root@txp-virtual-machine:/home/txp# g++ test.cpp
root@txp-virtual-machine:/home/txp#


注:

  • 与转换构造函数具有同等的地位

  • 使得编译器有能力将对象转化为其它类型

  • 编译器能够隐式的使用类型转换函数


2、类类型之间的转换:

这个问题也是之前我们上面简单的测试,不能进行类类型之间的转换;现在我们学习了类型转换函数,是可以进行转换的:

代码版本一:

#include <iostream>
#include <string>

using namespace std;

class Test;

class Value
{
public:
    Value()
    {
    }
    explicit Value(Test& t)
    {
    }
};

class Test
{
    int mValue;
public:
    Test(int i = 0)
    {
        mValue = i;
    }
    int value()
    {
        return mValue;
    }
    operator Value()
    {
        Value ret;
        cout << "operator Value()" << endl;
        return ret;
    }
/*工程上通过以下方式;
  Value toValue()
  {
      Value ret;
      
      return ret;
  
  }
};

int main()
{   
    Test t(100);
    Value v = t;
   
    return 0;
}

输出结果(编译通过):

root@txp-virtual-machine:/home/txp# g++ test.cpp
root@txp-virtual-machine:/home/txp#


注意:这里还有一种让编译器犯难的转换写法;我们上面这样写是用explicit关键字屏蔽了Value类里面的隐式转换,所以不会犯难,下面是犯难的代码示例

#include <iostream>
#include <string>

using namespace std;

class Test;

class Value
{
public:
    Value()
    {
    }
     Value(Test& t)
    {
    }
};

class Test
{
    int mValue;
public:
    Test(int i = 0)
    {
        mValue = i;
    }
    int value()
    {
        return mValue;
    }
    operator Value()
    {
        Value ret;
        cout << "operator Value()" << endl;
        return ret;
    }
};

int main()
{   
    Test t(100);
    Value v = t;
   
    return 0;
}

输出结果:

root@txp-virtual-machine:/home/txp# g++ test.cpp
test.cpp: In function ‘int main()’:
test.cpp:42:15: error: conversion from ‘Test’ to ‘Value’ is ambiguous
     Value v = t;
               ^
test.cpp:41:10: note: candidates are:
     Test t(100);
          ^
test.cpp:31:5: note: Test:perator Value()
     operator Value()
     ^
test.cpp:14:6: note: Value::Value(Test&)
      Value(Test& t)

3、小结:

  • 无法抑制隐式的类型转换函数调用

  • 类型转换函数可能与转换构造函数起冲突

  • 当然工程中可能比较习惯用 Type toType()的公有成员代替类型转换函数(就是换了种写法)


好了,今天的分享就到这里,如果文章中有错误或者不理解的地方,可以交流互动,一起进步。


收藏 评论0 发布时间:2020-8-29 23:30

举报

0个回答

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版