【Cpp】第十五章-类型转换

类型转换

C中的类型转换

  C语言中的类型转换分为隐式类型转换强制类型转换两种

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
int main()
{
//隐式类型转换
int i = 10;
double d = i;
printf("%d, %.2lf\n", i, d);
//强制类型转换
i = (int)d;
printf("%d, %.2lf\n", i, d);
}

  这种从C中继承而来的类型转换方式十分不直观,可视性较差,不便于我们在发生错误时查找错误。
  为了解决这种问题,于是Cpp中新诞生了四种更加直观更加安全的类型转换操作。

Cpp中的类型转换

static_cast

  static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast,但它不能用于两个不相关的类型进行转换。

1
2
3
4
5
6
7
8
9
10
#include <iostream>
int main()
{
double d = 10.2;
int i = static_cast<int>(d);
std::cout << "d:" << d << " i:" << i << std::endl;
}


d:10.2 i:10

  static_cast是一个模板函数,如上使用就可以完成类型的转换,

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
int main()
{
//double d = 10.2;
//int i = static_cast<int>(d);
//std::cout << "d:" << d << " i:" << i << std::endl;
int i = 10;
int *p = &i;
int address = static_cast<int>(p);
}


invalid static_cast from type 'int*' to type 'int'

  但是如上的类型转换就报错了,说明static_cast是无法将int*转为int的,如果两个类型毫无关系则无法进行转换。

reinterpret_cast

  reinterpret_cast是一种十分危险的类型转换,它用于指针,引用以及可以容纳指针的整数类型之间的转换,之所以说它危险是你甚至可以将一个类型指针任意转换为其他类型的指针,比如将int*转换为string*,于是这个指针的命运由此就彻底改变了,使用不当就内存访问越界程序崩溃。

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
int main()
{
int i = 10;
double d;
int* p = &i;
//将指针强转为整形
long long address = reinterpret_cast<long long>(p);
std::cout << p << " " << address;
}


0x61fe0c 6422028

const_cast

  const_cast可以完成从const对象到non-const对象的转换.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
int main()
{
const int i = 10;
std::cout << i << std::endl;
int& r = const_cast<int&>(i);
r = 11;
std::cout << i << std::endl;
std::cout << r << std::endl;
const int a = 2;
int *p = const_cast<int*>(&a);
*p = 3;

std::cout << a << std::endl;
std::cout << *p << std::endl;
}

  经过类型强转后我们发现确实可以更改指向常量的引用或指针了,但是通过输出对比我们发现,引用和指针指向的数据被改变了但是原数据并没有被改变,这是因为编译器的优化导致的,导致编译器并没有实际从内存中去取这块内存,而是重新分配了一块内存,我们可以使用volatile关键字来防止编译器的优化。

dynamic_cast

  dynamic_cast可以完成从父类到子类的指针或者引用的强制类型转换。从子类到父类的转换我们有切割帮我们进行隐式类型转换,但是从父类到子类是不能自动转换的,我们只能通过dynamic_cast来强制转换引用和指针,并且只能在有虚函数的类中进行转换。dynamic_cast在转换前会先进行转换实验,如果能转换成功则转换,转换不成功则返回0。
  Cpp之所以可以完成类型的转换,多亏与Cpp的RTTI机制,即运行时类型识别。虽然源文件中存储着类型以及之间的继承关系,但是其只用于编译,在程序运行时是无法拿到这些信息,于是Cpp为了可以在运行时获取数据对象的类信息以及继承关系便诞生了RTTIdynamic_casttypeidRTTI的典型应用。

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 <iostream>
class Parent
{
public:
virtual void Func()
{

}
int s = 10;
};
class Son : public Parent
{
public:
int s = 11;
};
int main()
{
Parent* p = new Parent;
std::cout << p->s << std::endl;
Son* s = dynamic_cast<Son*>(p);
if(s == nullptr)
{
std::cout << "change error" << std::endl;
return -1;
}
std::cout << s->s << std::endl;
}


11
change error

explicit

  这个参数之前已经在类和对象中讲解过了,这个参数加在类的构造函数前用于禁用构造函数函数参数的隐式转换。
  未禁用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
class Test
{
public:
Test(int test)
:_test(test)
{
std::cout << "construct" << std::endl;
}
private:
int _test;
};
int main()
{
Test test = 10;
}



construct

  禁用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
class Test
{
public:
explicit Test(int test)
:_test(test)
{
std::cout << "construct" << std::endl;
}
private:
int _test;
};
int main()
{
Test test = 10;//编译不过
}

-------------本文结束感谢您的阅读!-------------
记录学习每一分,感谢您的赞助