【C++】 --- 强制转换运算符

简介: 【C++】 --- 强制转换运算符

1. 隐式转换

C/C++中的类型转换分为两种:隐式类型转换和显示类型转换。

隐式类型转换服从向下兼容的原则:

char x = 5;
int    y = x; //将char转换为int,即是隐式转换

2. 显示转换(强制类型转换

C语言中典型的强制类型转换

int *p = (char *) x;

C++对C兼容,上面的转换方式是可行的,但是有时候会有问题,所以C++新增了四个强制类型转换关键字

const_cast<type> (expr): const_cast 运算符用于修改类型的 const / volatile 属性。除了 const 或 volatile 属性之外,目标类型必须与源类型相同。这种类型的转换主要是用来操作所传对象的 const 属性,可以加上 const 属性,也可以去掉 const 属性。
dynamic_cast<type> (expr): dynamic_cast 在运行时执行转换,验证转换的有效性。如果转换未执行,则转换失败,表达式 expr 被判定为 null。dynamic_cast 执行动态转换时,type 必须是类的指针、类的引用或者 void*,如果 type 是类指针类型,那么 expr 也必须是一个指针,如果 type 是一个引用,那么 expr 也必须是一个引用。
reinterpret_cast<type> (expr): reinterpret_cast 运算符把某种指针改为其他类型的指针。它可以把一个指针转换为一个整数,也可以把一个整数转换为一个指针。
static_cast<type> (expr): static_cast 运算符执行非动态转换,没有运行时类检查来保证转换的安全性。例如,它可以用来把一个基类指针转换为派生类指针。

2.1 const_cast应用举例

用于删除 const、volatile 和 __unaligned 特性(如将 const int 类型转换为 int 类型 )

1> const_cast可用于更改const成员函数内的非const类成员。看下面的示例代码

#include <iostream>
using namespace std;
class student 
{ 
private: 
    int roll; 
public: 
    // 构造函数
    student(int r):roll(r) {} 
    // 在const_cast的帮助下改变roll的const函数
    void fun() const
    { 
        ( const_cast <student*> (this) )->roll = 5; 
    } 
    int getRoll()  { return roll; } 
}; 
int main(int argc, char const *argv[])
{
    student s(3); 
    cout << "Old roll number: " << s.getRoll() << endl; 
    s.fun(); 
    cout << "New roll number: " << s.getRoll() << endl; 
  return 0;
}

编译输出结果;

2> const_cast可用于将const数据传递给不接收const的函数。例如:

#include <iostream>
using namespace std;
int fun(int* ptr) 
{ 
    return (*ptr + 10); 
} 
int main(int argc, char const *argv[])
{
    const int val = 10; 
    const int *ptr = &val; 
    int *ptr1 = const_cast <int *>(ptr); 
    cout << fun(ptr1)<<endl; 
  return 0;
}

编译输出:

3> const_cast也可以用来抛弃volatile属性。例如:

#include <iostream>
#include <typeinfo>  // typeid
using namespace std;
int main(int argc, char const *argv[])
{
    int a1 = 40; 
    const volatile int* b1 = &a1; 
    cout << "typeid of b1 " << typeid(b1).name() << '\n'; 
    int* c1 = const_cast <int *> (b1); 
    cout << "typeid of c1 " << typeid(c1).name() << '\n'; 
  return 0;
}

编译输出:

2.2 reinterpret_cast

它用于转换任何类型的另一个指针的一个指针,而不管该类是否相互关联。它不检查指针类型和指针所指向的数据是否相同。

用法如下:

reinterpret_cast <数据类型*>(指针变量);

看一个示例:

#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
    int* p = new int(65); 
    char* ch = reinterpret_cast<char*>(p); 
    cout << *p << endl; 
    cout << *ch << endl; 
    cout << p << endl; 
    cout << ch << endl; 
  return 0;
}

编译输出:

2.3 dynamic_cast

dynamic_cast的转换格式:

dynamic_cast <type-id> (expression)

将expression转换为type-id类型,type-id必须是类的指针、类的引用或者是void *;如果type-id是指针类型,那么expression也必须是一个指针;如果type-id是一个引用,那么expression也必须是一个引用。

最简单的上行转换,比如Derived 继承自Basic,Derived 转换为Basic,进行上行转换时,是安全的,如下:

#include <iostream>
using namespace std;
class Basic{
     public:
          virtual int test(){return 0;}  // 必须为多态以使用运行时检查的 dynamic_cast
};
class Derived : public Basic{
     public:
          int test(){return 1;}
};
int main(int argc, char const *argv[]){
     Basic      cBasic;
     Derived    cDerived;
     Basic * pB1 = new Basic;
     Basic * pB2 = new Derived;
     //动态强制转换失败,因此pD1为空。
     Derived * pD1 = dynamic_cast<Derived * > (pB1);   
     //动态强制转换成功,因此rD2引用派生对象。
     Derived & rD2 = dynamic_cast<Derived &> (*pB2);   
     return 0;
} 

编译结果:

2.4 static_cast

static_cast通常用于转换数据类型(float->int)

1> 代码段一示例

#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
  float f = 4.5;
  int a = f; //C-style
  int b = static_cast<int>(f);
  cout << b << endl;
  return 0;
}

编译输出:

2> 对上面的代码进行修改

#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
  int a = 10;
  char c = 'a';
  int* q = (int*) &c;
  int *p = static_cast<int *>(&c);//编译错误,static_cast 不能将字符转换成指针
  return 0;
}

编译输出:

这意味着,即使您认为可以将特定对象类型转换为另一个对象,但这是非法的,static_cast也不允许这样做。

static_cast 用于基本数据类型之间的转换,如把int转换成char,把int转换成float。在c++ primer 中说道:c++ 的任何的隐式转换都是使用 static_cast 来实现。

3> 让我们以继承为例,来看看这个例子:

#include <iostream>
using namespace std;
class Base { 
}; 
class Derived : public Base { 
}; 
int main(int argc, char const *argv[])
{
    Derived d1; 
    Base* b1 = (Base*)(&d1); // 允许 
    Base* b2 = static_cast<Base*>(&d1); 
  return 0;
}

编译输出:

编译,上面的代码将不会出现任何错误。

1、我们取&d1,显式的存入Base中,存储在b1中。

2、我们取&d1,用static_cast将其转换成Base,存储在b2中。

我们知道static_cast执行严格的类型检查,让我们稍微修改一下代码看看,把继承改为private。

4>

#include <iostream>
using namespace std;
class Base { 
}; 
class Derived :  private Base { 
}; 
int main(int argc, char const *argv[])
{
    Derived d1; 
    Base* b1 = (Base*)(&d1); // 允许 
    Base* b2 = static_cast<Base*>(&d1); 
  return 0;
}

编译输出:

即使继承为受保护的,上面的代码也不会编译。因此,要使用static_cast,请将其继承为public。

5> 使用static_cast将“向空指针”和“从空指针”进行强制转换。例子:

#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
    int i = 10; 
    void* v = static_cast<void*>(&i); 
    int* ip = static_cast<int*>(v); 
  return 0;
}

编译输出:

参看链接:

https://www.runoob.com/cplusplus/cpp-casting-operators.html

https://blog.csdn.net/chen1415886044/article/details/104565863

https://www.cnblogs.com/Allen-rg/p/6999360.html

相关文章
|
5月前
|
C++
C++类自加自减与<<运算符的重载实现
C++类自加自减与<<运算符的重载实现
|
5月前
|
C++
C++程序中的赋值运算符
C++程序中的赋值运算符
55 2
|
1月前
|
C++
【C++基础】运算符详解
这篇文章详细解释了C++中运算符的用法,包括算术运算符、赋值运算符、比较运算符和逻辑运算符,以及它们在表达式中的作用和示例。
22 2
|
2月前
|
C++
c++学习笔记02 运算符
C++学习笔记,介绍了C++中的运算符,包括基本的加减乘除、求模、前后置递增递减、赋值运算符、比较运算符和逻辑运算符的使用及其注意事项。
37 6
|
5月前
|
算法 C++ 开发者
【C++运算符重载】深入理解C++中的流运算符 >>和<<重载
【C++运算符重载】深入理解C++中的流运算符 >>和<<重载
78 0
|
4月前
|
C++
C++之运算符
C++之运算符
|
4月前
|
安全 程序员 C++
C++一分钟之-重载运算符
【6月更文挑战第21天】C++的运算符重载让程序员能为自定义类型定制运算符行为,增强代码表达力。但要注意清晰性、优先级和返回类型。遵循运算符原有意义,充分测试,并用注释解释非直观设计。示例展示了如何为复数类重载`+`运算符。避免重载内置类型,注意结合性,且慎用隐式转换。重载应提升可读性而非复杂化代码。
43 2
|
4月前
|
C++
C++一分钟之-理解C++的运算符与表达式
【6月更文挑战第18C++的运算符和表达式构成了编程的基础,涉及数学计算、逻辑判断、对象操作和内存管理。算术、关系、逻辑、位、赋值运算符各有用途,如`+`、`-`做加减,`==`、`!=`做比较。理解运算符优先级和结合律至关重要。常见错误包括优先级混淆、整数除法截断、逻辑运算符误用和位运算误解。解决策略包括明确优先级、确保浮点数除法、正确使用逻辑运算符和谨慎进行位运算。通过实例代码学习,如 `(a &gt; b) ? &quot;greater&quot; : &quot;not greater&quot;`,能够帮助更好地理解和应用这些概念。掌握这些基础知识是编写高效、清晰C++代码的关键。
34 3
|
5月前
|
C++ 编译器