类型转换函数(三十五)

2023-05-15,,

        我们之前在 C 语言中讲过类型转换,那么在 C++ 中是否还会有什么新特性呢?我们先来看看之前的类型转换是怎样的,标准数据类型之间会进行隐式的类型安全转换。转换规则如下

        我们还是以代码为例来进行分析

#include <iostream>
#include <string>

using namespace std;

int main()
{
    short s = 'a';
    unsigned int ui = 100;
    int i = -200;   // safe
    double d = i;   // safe
    
    cout << "d = " << d << endl;
    cout << "ui = " << ui << endl;
    
    if( (ui + i) > 0 )
    {
        cout << "Positive" << endl;
    }
    else
    {
        cout << "Negative" << endl;
    }
    
    cout << "sizeof(s + 'b') = " << sizeof(s + 'b') << endl;
    
    return 0;
}

        我们来试着打印下 d 和 ui 的值,如果 ui + i > 0,则打印 Positive,否则打印 Negative。最后看看 short 和 char 类型会转换成 short 吗?看看编译结果

        我们看到打印的是 Positive,也就说 ui + i > 0。根据数学知识,怎么可能呢?我们一会再来打印下他们相加的值看看,最后一个竟然打印的是 4,short 类型不是 2 吗?再看看我们上面的隐式类型转换规则,short 和 char 都会转换成 int 类型。而 int 也会隐式转换成 unsigned int,所以结果并不惊奇,我们来看看他们相加的值是多少?

        我们看到他们相加是个那么大的随机数,这肯定大于 0 啦。那么在 C++ 中问题来了:普通类型与类类型之间能否进行类型转换?类类型之间能否进行类型转换?下来我们来看看示例代码

#include <iostream>
#include <string>

using namespace std;

class Test
{
    int mValue;
public:
    Test()
    {
        mValue = 0;
    }
    
    Test(int i)
    {
        mValue = i;
    }
    
    Test operator + (const Test& t)
    {
        Test ret(mValue + t.mValue);
        
        return ret;
    }
    
    int value()
    {
        return mValue;
    }
};

int main()
{
    Test t;
    
    t = 5;
    
    cout << "t.value() = " << t.value() << endl;
    
    Test r;
    
    r = t + 10;
    
    cout << "r.value() = " << r.value() << endl;
    
    return 0;
}

        我们来看看这样直接 t = 5,和 r = t + 10;可以通过吗?看看编译结果

        我们看到编译通过了,并且也执行成功。下来我们来分析下为什么会支持这样的写法,在构造函数中可以定义不同类型的参数,参数满足这三个条件时便称之为转换构造函数:a> 有且仅有一个参数;b> 参数是基本类型;c> 参数是其它类类型。那么我们从 C 的角度来看看强制类型转换:int i = int(1.5);Test t = Test(100);这样便不难解释了,为了显示编译器的强大,编译器会尽力尝试让源码通过编译,如下

        编译尽力尝试的结果便是隐式类型转换,使用转换构造函数来进行转换。但是隐式类型的转换会让程序以意想不到的方式进行工作,是工程中的 bug 的重要来源。如果在那块我们只是手误写成那样了,编译器却让它通过了,我们看到运行结果不对,bug 却无从查起。。。

        所以为了解决这个问题,我们便在工程中通过 explicit 关键字来杜绝编译器的转换尝试,转换构造函数被 explicit 修饰时只能进行显示转换,转换方式是:a> static_cast <ClassName>(value);b> ClassName(value);c> (ClassName)value;但是在 C++ 中我们推荐的是第一种写法,最后一种往往是不推荐的。下来我们就来试试 explicit 关键字,在 Test(int i) 成员函数前加上,看看编译器还会不会进行隐式类型转换

        那么编译器直接报错了,我们再来试试手动的进行类型转换,我们将第 37 和 43 行改为下面那样

    t = static_cast<Test>(5);
    
    r = t + static_cast<Test>(10);

        我们来看看编译结果

        结果和我们之前的是一样的。那么从普通类型能够转换到类类型,类类型能否转换到普通类型呢?我们在 C++ 类中可以定义类型转换函数类型转换函数用于将类对象转换为其它类型,语法规则如下

        下来我们来试试编写类型转换函数

#include <iostream>
#include <string>

using namespace std;

class Test
{
    int mValue;
public:
    Test(int i)
    {
        mValue = i;
    }
    
    int value()
    {
        return mValue;
    }
    
    operator int ()
    {
        return mValue;
    }
};

int main()
{
    Test t(100);
    int i = t;
    
    cout << "t.value() = " << t.value() << endl;
    cout << "i = " << i << endl;
    
    return 0;
}

        我们来试试看这样行不行呢,编译结果如下

        我们看到类对象已经成功转换为普通数据类型。那么类型转换函数具有以下几个特点:a> 与转换构造函数具有相等的地位;b> 使得编译器有能力将对象转化为其它类型;c> 编译器能够隐式的使用类型转换函数。同样,编译器也会尽量尝试让源码通过编译,如下

        那么便不难解释我们上面的程序了。既然这样都可以转换,类类型之间可以相互转换吗?我们来看看

#include <iostream>
#include <string>

using namespace std;

class Value
{
public:
    Value()
    {
    }
};

class Test
{
    int mValue;
public:
    Test(int i)
    {
        mValue = i;
    }
    
    int value()
    {
        return mValue;
    }
    
    operator Value ()
    {
        Value ret;
        
        return ret;
    }
};

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

        那么我们看到 Test 和 Value 是两个不同的类,它们能转换成功吗?我们来看看编译结果

        编译通过,当然没什么输出了,我们在程序中又没有什么打印语句。那么如果我们在类 Value 中加上转换构造函数呢?编译器会作何选择?这时我们的 VAlue 类将会变成

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

        我们来编译下看看结果

        编译器报错了,它犯难了。这是不知道是调用 Test 类的类型转换函数还是 Value 类的转换构造函数了,像这种情况,我们在转换构造函数前加上 explicit 关键字,编译器便不会去隐式的调用转换构造函数了。我们在类型转换函数中加上一句输出,看看结果

        我们可以看出调用的确实是类型转换函数。那么我们无法抑制隐式的类型转换函数调用,类型转换函数便可能与转换构造函数造成冲突,工程中以 Type toType() 的共有成员函数代替类型转换函数。

        通过对类型转换函数的学习,总结如下:1、转换构造函数只有一个参数;2、转换构造函数的参数类型是其它类型,它在类型转换时被调用;3、隐式类型转换时工程中 bug 的重要来源,explicit 关键字用于杜绝隐式类型转换;4、C++ 类中可以定义类型转换函数;5类型转换函数用于将类对象转换为其它类型,它与转换构造函数具有同等的地位;6、工程中以 Type toType() 的共有成员函数代替类型转换函数。

        欢迎大家一起来学习 C++ 语言,可以加我QQ:243343083

《类型转换函数(三十五).doc》

下载本文的Word格式文档,以方便收藏与打印。