0%

C++隐式类型转换

C++隐式类型转换

隐式类型转换

在C++语言中,类型转换有两种方式,隐式类型转换和显示类型转换。在有隐式类型转换的表达式中,使用者不需要明确指定一个类型的对象该转换为另外哪一个类型,这个工作将隐含地由编译器来完成,编译器将分析表达式的含义,进行类型转换。隐式类型转换针对不同的类型有不同的转换方式,总体可以分为两种类型:(显示类型转换即为 static_cast …这些关键字)

  • 算术类型
  • 类类型

算术类型转换

低精度的变量给高精度变量赋值会发生隐式类型转换。算术类型转换的设计原则就是尽可能避免损失精度。

类类型转换

在类类型转换中,我们通常有两个需求,一个是将其他类型的数据转换为我们自定义类的类型,另一个是将自定义类的类型在需要的时候转换为其他的数据类型。在C++中,可以前者可以通过定义单参数构造函数实现,后者通过定义转换函数来进行类类型转换。这种方式也称为用户定义的转换(User-Defined Conversion)。这种方式在使用的时候不需要指明转换类型,而是由编译器自动进行选择转换函数,所以也是一种隐式类型转换。

编译器每次只能执行一种类类型的转换。如果一个对象需要从类型A自动转换为类型C,则类型A必须有直接转换为类型C的函数。

转换构造函数

如果一个类的某个构造函数只接受一个参数,且没有被声明为explicit,则它实际上定义了将这个参数的类型转换为此类类型的隐式转换机制,我们把这种构造函数称为转换构造函数。在转换构造函数中只允许一步类类型的转换。可以通过将构造函数声明为explicit来阻止隐式转换。

最常见的例子就是将C类型字符串转换为string类型。string(const char *s)。自定义类的转换 如下例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std ;
class BOOK //定义了一个书类
{
private:
string _bookISBN ; //书的ISBN号
float _price ; //书的价格

public:
//定义了一个成员函数,这个函数即是那个“期待一个实参为类类型的函数”
//这个函数用于比较两本书的ISBN号是否相同
bool isSameISBN(const BOOK & other ){
return other._bookISBN==_bookISBN;
}

//类的构造函数,即那个“能够用一个参数进行调用的构造函数”(虽然它有两个形参,但其中一个有默认实参,只用一个参数也能进行调用)
BOOK(string ISBN,float price=0.0f):_bookISBN(ISBN),_price(price){}
};

int main()
{
BOOK A("A-A-A");
BOOK B("B-B-B");

cout<<A.isSameISBN(B)<<endl; //正经地进行比较,无需发生转换

cout<<A.isSameISBN(string("A-A-A"))<<endl; //此处即发生一个隐式转换:string类型-->BOOK类型,借助BOOK的构造函数进行转换,以满足isSameISBN函数的参数期待。
cout<<A.isSameISBN(BOOK("A-A-A"))<<endl; //显式创建临时对象,也即是编译器干的事情。
}

类型转换函数

类型转换函数一般形式,虽然实现这种方式,可以通过系定义函数来返回对应的值,但是也可以像下面这样写。另外

输入操作符 >> 是二元操作符,返回做操作数作为其表达式结果,因此cin >> num返回cin,然而cin是输入流istream的对象,该对象能出现在条件表达式中,是因为在istream中定义了类型转换函数 operator bool()

1
2
3
4
5
operator 目标类型()
{
...
return 目标类型数据;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class A {
public:
A(const int x) : _x(x) {}
operator int() { return _x; }
private:
int _x;
};

int main () {
A a(10);
int res = a + 20;
std::cout << res << std::endl; // 输出结果为30.
}