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

Posted Overboom

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 属性。除了 constvolatile 属性之外,目标类型必须与源类型相同。这种类型的转换主要是用来操作所传对象的 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

以上是关于C++ --- 强制转换运算符的主要内容,如果未能解决你的问题,请参考以下文章

C++ 强制转换运算符重载和多态性

重载强制转换运算符时的 C++ 歧义

是否可以强制转换 c++ 运算符新输出? [关闭]

如何在 Visual C++ 2015 中的 C++ 强制转换运算符的尖括号内保留空格?

c ++:强制转换运算符与分配运算符与转换构造函数优先级

C++基础语法梳理:智能指针和强制类型转换运算符