【C++知识点】类型转换

简介: 【C++知识点】类型转换

C/C++知识点

C++类型转换

旧式转型 C 风格的强制类型:

TYPE b = (TYPE) a

例如:

int i = 48; 
char c = (char) i;

新式转型 C++ 风格的类型转换提供了 4 种类型转换操作符来应对不同场合的应用。

TYPE b = 类型操作符 ( a )


类型操作符 = static_cast | reinterpreter_cast | dynamic_cast | const_cast

static_cast


静态类型转换(斯文的劝导,温柔的转换),类似于 C 语言中的隐式转换,如 int 转换成 char 。

主要用法:


用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。上行指针或引用(派生类到基类)转换安全,下行(基类到派生类)转换不安全。


用于基本数据类型之间的转换,如把 int 转换成 char ,把 int 转换成 enum 。这种转换的安全性也要开发人员来保证。


把空指针转换成目标类型的空指针。


把任何类型的表达式转换成 void 类型。

#include <iostream>
using namespace std;
class Animal {
public:
  virtual void cry() = 0;
};
class Cat :public Animal
{
public:
  void cry()
  {
    cout << "喵喵瞄" << endl;
  }
};
class Dog :public Animal
{
public:
  void cry()
  {
    cout << "汪汪汪" << endl;
  }
};

用法一:父子类之间的类型转换

Dog* dog1 = new Dog();
Animal* a1 = static_cast<Animal*>(dog1); //子类的指针转型到父类指针
Dog* dog1_1 = static_cast<Dog*>(a1);     //父类的指针转型到子类的指针
//父子到子类,有风险,虽然下面这句不会报错,但是狗类转换成猫类是完全错误的做法
Cat* cat1 = static_cast<Cat*>(a1);
Dog dog2;
Animal& a2 = static_cast<Animal&>(dog2); //子类的引用转型到父类的引用
Dog& dog2_2 = static_cast<Dog&>(a2);     //父类到子类引用


用法二:基本类型的转换

int  kk = 234;
char cc = static_cast<char>(kk);


用法三:把空指针转换成目标类型的空指针

int* p = static_cast<int*>(NULL);
Dog* dp = static_cast<Dog*>(NULL);


用法四:把任何类型的表达式转换成 void 类型

int* pi = new int[10];
void* vp = static_cast<void*>(pi);

reinterpret_cast

重新解释类型(挂羊头,卖狗肉))不同类型间的互转,数值与指针间的互转。

用法: TYPE b = reinterpret_cast ( a )

TYPE 必须是一个指针、引用、算术类型、函数指针


忠告: 滥用 reinterpret_cast 运算符可能很容易带来风险。 除非所需转换本身是低级别的,否则应使用其他强制转换运算符之一。

#include <iostream>
using namespace std;
class Animal {
public:
  void cry() {
    cout << "动物叫" << endl;
  }
};
class Cat :public Animal
{
public:
  void cry()
  {
    cout << "喵喵瞄" << endl;
  }
};
class Dog :public Animal
{
public:
  void cry()
  {
    cout << "汪汪汪" << endl;
  }
};

用法一:数值与指针之间的转换

int* p = reinterpret_cast<int*>(0x99999);
int val = reinterpret_cast<int>(p);

用法二:不同类型指针和引用之间的转换

Dog  dog1;
Animal* a1 = &dog1;
a1->cry();  //动物叫
Dog* dog1_p = reinterpret_cast<Dog*>(a1);
Dog* dog2_p = static_cast<Dog*>(a1);   //如果能用static_cast ,static_cast 优先
dog1_p->cry();  //汪汪汪
dog2_p->cry();  //汪汪汪
//Cat* cat1_p = static_cast<Cat*>(a1);  //输出喵喵喵
//Cat* cat2_p = static_cast<Cat*>(dog1_p); //报错,不同类型指针转换不能使用static_cast
Cat* cat2_p = reinterpret_cast<Cat*>(dog1_p); //但是这个强制转换不会报错
cat2_p->cry();  //喵喵喵
Animal& a2 = dog1;
Dog& dog3 = reinterpret_cast<Dog&>(a2);//引用强转用法

dynamic_cast


动态类型转换


将一个基类对象指针 cast 到继承类指针,dynamic_cast 会根据基类指针是否真正指向继承类指针来做相应处理。失败返回 null ,成功返回正常 cast 后的对象指针。


将一个基类对象引用 cast 继承类对象,dynamic_cast 会根据基类对象是否真正属于继承类来做相应处理。失败抛出异常 bad_cast 。

#include <iostream>
using namespace std;
class Animal {
public:
  virtual void cry() = 0;
};
class Cat :public Animal
{
public:
  void cry()
  {
    cout << "喵喵瞄" << endl;
  }
  void play()
  {
    cout << "爬爬树"<<endl;
  }
};
class Dog :public Animal
{
public:
  void cry()
  {
    cout << "汪汪汪" << endl;
  }
  void play()
  {
    cout << "溜达溜达" << endl;
  }
};

用法一:指针类型转换

void animalPlay(Animal* animal) {
  animal->cry();
  Dog* pDog = dynamic_cast<Dog*>(animal);
  if (pDog) {
    pDog->play();
  }
  else { //pDog == NULL
    cout << "不是狗,别骗我!" << endl;
  }
  Cat* pCat = dynamic_cast<Cat*>(animal);
  if (pCat) {
    pCat->play();
  }
  else { //pDog == NULL
    cout << "不是猫,别骗我!" << endl;
  }
}
int main() {
  Dog* dog1 = new Dog();
  Animal* a1 = dog1;
  animalPlay(a1);
  cout << endl;
  Cat* cat1 = new Cat();
  Animal* a2 = cat1;
  animalPlay(a2);
  return 0;
}


c0be1e8390aa42a988f27346df213955.png

用法二:引用类型转换

void animalPlay(Animal& animal) {
  animal.cry();
  try {
    Dog& pDog = dynamic_cast<Dog&>(animal);
    pDog.play();
  }
  catch (std::bad_cast bc) {
    cout << "不是狗,那应该是猫" << endl;
  }
  try {
    Cat& pCat = dynamic_cast<Cat&>(animal);
    pCat.play();
  }
  catch (std::bad_cast bc) {
    cout << "不是猫,那应该是上面的狗" << endl;
  }
}
int main() {
  Dog* dog1 = new Dog();
  Dog dog2;
  animalPlay(dog2);
  cout << endl;
  Cat* cat1 = new Cat();
  Cat cat2;
  animalPlay(cat2);
  return 0;
}



1ab6ef76d74f4387a17c086e08840fcb.png

const_cast

去掉 const 属性。(仅针对于指针和引用)

#include <iostream>
using namespace std;
void demo(const char* p)
{
  //对指针去掉cost 重新赋值
  char* p1 = const_cast<char *>(p);
  p1[0] = 'A';
  //直接去掉const修改
  const_cast<char*>(p)[1] = 'B';
  cout << p << endl;
}
void demo(const int p)
{
  int q = p;
  //const_cast<int>(p) = 888;//报错,不能对非指针和引用进行const 转换
  cout << p << endl;
}
int main(void)
{
  //字符串数组
  //char p[] = "12345678";
  //demo(p);  //合情合理
  //常量字符串不能去掉const 修改
  //警告: 在去掉常量限定符之前,保证指针所指向的内存能够修改,不能修改则会引起异常。
  const char* cp = "987654321";
  demo(cp);
  system("pause");
  return 0;
}


类型转换使用建议


1)static_cast 静态类型转换,编译的时 c++ 编译器会做编译时的类型检查(隐式转换)。基本类型转换,父子类之间合理转换。


2)若不同类型之间,进行强制类型转换,用 reinterpret_cast<>() 进行重新解释。


注意: C 语言中能隐式类型转换的,在 c++ 中可用 static_cast<>() 进行类型转换,因 c++ 编译器在编译检查一般都能通过;C 语言中不能隐式类型转换的,在 c++ 中可以用 reinterpret_cast<>() 进行强制类型解释。


总结: static_cast<>() 和 reinterpret_cast<>() 基本上把C语言中的强制类型转换给覆盖,注意 reinterpret_cast<>() 很难保证移植性。


3)dynamic_cast<>() ,动态类型转换,安全的虚基类和子类之间转换,运行时类型检查。


4)const_cast<>() ,去除变量的只读属性。


最后的忠告: 程序员必须清楚的知道 —— 要转的变量,类型转换前是什么类型,类型转换后是什么类型,转换后有什么后果。


C ++大牛建议: 一般情况下,不建议进行类型转换,避免进行类型转换。

目录
相关文章
|
8月前
|
安全 编译器 程序员
【C++】C++的类型转换
【C++】C++的类型转换
|
2月前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
136 5
|
8月前
|
存储 安全 编译器
C++:现代类型转换
C++:现代类型转换
60 5
|
3月前
|
编译器 C语言 C++
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
39 1
|
3月前
|
存储 编译器 数据安全/隐私保护
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解2
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
56 3
|
3月前
|
编译器 C++
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解1
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
62 3
|
3月前
|
C++
C++入门4——类与对象3-2(构造函数的类型转换和友元详解)
C++入门4——类与对象3-2(构造函数的类型转换和友元详解)
35 0
|
7月前
|
存储 网络协议 编译器
【干货总结】Linux C/C++面试知识点
Linux C/C++基础与进阶知识点,不仅用于面试,平时开发也用得上!
664 18
|
6月前
|
存储 安全 编译器
【C++11】类型转换
【C++11】类型转换
50 0
|
6月前
|
安全 程序员 编译器
C++一分钟之-C++中的类型转换
【7月更文挑战第8天】C++中的类型转换涉及隐式和显式操作,隐式转换如从`int`到`double`是自动的,但可能导致数据丢失。显式转换包括`static_cast`, `dynamic_cast`, `const_cast`, `reinterpret_cast`,以及转换构造函数。要避免数据丢失、类型不匹配和运行时错误,需谨慎使用显式转换并检查结果。过度使用`reinterpret_cast`应避免。理解这些转换有助于编写更安全的代码。
53 0