C++四种强制转换
  PjuqN0S4qpGM 2023年11月02日 32 0


C++的四种强制类型转换,所以C++不是类型安全的。分别为:static_cast , dynamic_cast , const_cast , reinterpret_cast。
  为什么使用C风格的强制转换可以把想要的任何东西转换成合乎心意的类型。那为什么还需要一个新的C++类型的强制转换呢?新类型的强制转换可以提供更好的控制强制转换过程,允许控制各种不同种类的强制转换。
  C++中风格是static_cast(content)。C++风格的强制转换其他的好处是,它们能更清晰的表明它们要干什么。程序员只要扫一眼这样的代码,就能立即知道一个强制转换的目的。

1、隐式类型转换

何时发生隐式类型转换?在下面这些情况下,编译器会自动地转换运算对象的类型:

- 在大多数表达式中,比int类型小的整型值首先提升为较大的整数类型;
- 在条件中,非布尔值转换为布尔类型;
- 初始化过程中,初始值转换成变量的类型;在赋值语句中,右侧运算对象转换成左侧运算对象的类型;
- 如果算术运算或关系运算的运算对象有多种类型,需要转换成同一种类型;
- 函数调用时也会发生类型转换。

除了算术转换之外还有几种隐式转换,包括如下几种:

1、数组转换成指针:

int ia[10];   //含有10个整数的数组
int *ip=ia;  //ia转换成指向数组首元素的指针

当数组被用作decltype关键字的参数,或者作为取地址符(&)、sizeof及typeid等运算符的运算对象时,上述转换不会发生。同样的,如果用一个引用来初始化数组,上述转换也不会发生。

2、指针的转换:C++还规定了几种其他转换方式,包括常量整数值0或字面值nullptr能转换成任意指针类型;指向任意非常量的指针能转换成void*;指向任意对象的指针能转换成const void*。

3、转换成布尔类型:存在一种从算术类型或指针类型向布尔类型自动转换的机制。如果指针或算术类型的值为0,转换结果为false;否则转换结果是true;

4、转换成常量:允许将指向非常量类型的指针转换成指向相应的常量类型的指针,对于引用也是这样。也就是说,如果T是一种类型,我们就能将指向T的指针或引用分别转换成指向const T的指针或引用。相反的转换不存在,因为它试图删除掉底层const。

5、类类型定义的转换:类类型能定义由编译器自动执行的转换,不过编译器每次只能执行一种类类型的转换。

2、显式类型转换

关于强制类型转换的问题,很多书都讨论过,写的最详细的是C++ 之父的《C++ 的设计和演化》。最好的解决方法就是不要使用C风格的强制类型转换,而是使用标准C++的类型转换符:static_cast, dynamic_cast。标准C++中有四个类型转换符:static_cast、dynamic_cast、reinterpret_cast、和const_cast。下面对它们一一进行介绍。

1、static_cast

用法:static_cast < type-id > ( expression )

说明:该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。

来源:为什么需要static_cast强制转换?

情况1:void指针->其他类型指针
情况2:改变通常的标准转换
情况3:避免出现可能多种转换的歧义

int c=static_cast<int>(7.987);//如果涉及到类的话,static_cast只能在有相互联系的类型中进行相互转换,不一定包含虚函数。

class A{};
class B:public A{};
class C{};

int main()
{ 
    A* a=new A;
    B* b; C* c;
    b=static_cast<B>(a); // 编译不会报错, B类继承A类
    c=static_cast<B>(a); // 编译报错, C类与A类没有任何关系
    return 0;
}

2、dynamic_cast

用法:dynamic_cast < type-id > ( expression )

说明:该运算符把expression转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void *;如果type-id是类指针类型,那么expression也必须是一个指针,如果type-id是一个引用,那么expression也必须是一个引用。

来源:为什么需要dynamic_cast强制转换?

简单的说,当无法使用virtual函数的时候。

【Note】:

(1)其他三种都是编译时完成的,dynamic_cast是运行时处理的,运行时要进行类型检查。
(2)不能用于内置的基本数据类型的强制转换。
(3)dynamic_cast转换如果成功的话返回的是指向类的指针或引用,转换失败的话则会返回NULL。
(4)使用dynamic_cast进行转换的,基类中一定要有虚函数,否则编译不通过。需要检测有虚函数的原因:类中存在虚函数,就说明它有想要让基类指针或引用指向派生类对象的情况,此时转换才有意义。 这是由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表, 只有定义了虚函数的类才有虚函数表。
(5)在类的转换时,在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的。在进行下行转换时,dynamic_cast具有类型检查的功能,比 static_cast更安全。

void doSomething(Flyable *obj)
{
    //name的返回值因系统而异,类型不同返回的字符串有所区别即可。
    cout << typeid(*obj).name() << endl;
    obj->takeoff();
    if(typeid(*obj) == typeid(Bird))
    {
        Bird *bird = dynamic_cast<Bird *>(obj);
        bird->foraging();
    }
    if(typeid(*obj) == typeid(Plane))
    {
        Plane *plane = dynamic_cast<Plane *>(obj);
        plane->carry();
    }
    obj->land();
}

3、reinpreter_cast

用法:reinpreter_cast (expression)

说明:type-id必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,在把该整数转换成原类型的指针,还可以得到原先的指针值)。它可以转化任何内置的数据类型为其他任何的数据类型,也可以转化任何指针类型为其他的类型。它甚至可以转化内置的数据类型为指针,无须考虑类型安全或者常量的情形。不到万不得已绝对不用。

4、const_cast

用法:const_cast (expression)

说明:该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。它可以使一个本来不是const类型的数据转换成const类型的,或者把const属性去掉。

常量指针被转化成非常量指针,并且仍然指向原来的对象;常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。

class B{

public:

int m_iNum;

}

void foo(){

const B b1;

b1.m_iNum = 100; //comile error

B b2 = const_cast<B>(b1);

b2. m_iNum = 200; //fine
}

上面的代码编译时会报错,因为b1是一个常量对象,不能对它进行改变;使用const_cast把它转换成一个常量对象,就可以对它的数据成员任意改变。注意:b1和b2是两个不同的对象。


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  8Tw5Riv1mGFK   18天前   29   0   0 C++
  BYaHC1OPAeY4   11天前   31   0   0 C++
  yZdUbUDB8h5t   14天前   22   0   0 C++
  oXKBKZoQY2lx   2天前   6   0   0 C++
PjuqN0S4qpGM