当前位置:   article > 正文

C/C++ 类型转换_c++转c

c++转c

C语言的强制类型转换与C++的四种转换类型的方式。
这篇博客将详细讲解其中的用法!



一、前言

类型转换在项目开发中是经常使用的,熟悉C语言的朋友,用的最多的应该是强制类型转换了,例如:
double d = 3.14; int a = (int)d;
这种方式确实可以,今天这篇博客重点讲解C++是如何类型转换的!

旧式转型 C风格的强制类型:
TYPE b = (TYPE) a
例如:
int i = 48;
char c = (char) i;

新式转型 C++风格的类型转换提供了4种类型转换操作符来应对不同场合的应用。
格式:
TYPE b = 类型操作符< TYPE > ( a )
类型操作符= static_cast | reinterpreter_cast | dynamic_cast | const_cast


二、类型转换

1. C语言类型转换

C语言的类型转换也就只有强制类型转换这一种,如下例子:

#include <iostream>

using namespace std;


int main1(void) {

	double radius = 7.54;

	int a1 = radius;		// 隐式类型转换
	int a2 = (int)radius;	// 强制类型转化,把double转成int

	char c = 'c';
	char *c1 = &c;
	int *a3 = (int *)c1;	// 指针也可以进行强制类型转换

	int* addr = (int *)0x66666;

	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

这没什么好讲的,大家都会!

2. C++类型转换

1). static_cast

静态类型转换(斯文的劝导,温柔的转换)。如int转换成char
主要用法:
a. 用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。上行指针或引用(派生类到基类)转换安全,下行不安全
b. 用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
c. 把空指针转换成目标类型的空指针。
d. 把任何类型的表达式转换成void类型。


定义一个Animal虚基类,里面有cry()虚函数;再定义两个派生类Cat和Dog,分别重写虚函数。

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;
	}
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  1. 第一种情况:父子类之间的类型转换

    Dog *dog1 = new Dog();
    Animal *d1 = static_cast<Animal *>(dog1);	// 子类的指针转型到父类指针
    
    Dog *dog2 = static_cast<Dog *>(d1);			// 父类的指针转型到子类指针
    Cat *cat1 = static_cast<Cat *>(d1);		// 这样是不可以的,虽然可以编译通过,但是不太建议这样使用
    
    
    Dog dog3;
    Animal &d2 = static_cast<Animal &>(dog3);	// 子类的引用转型到父类的引用
    
    Dog &dog4 = static_cast<Dog &>(d2);			// 父类的应用转型到子类的引用
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  2. 第二种情况:基本类型的转换

    int x = 123;
    char c = static_cast<char>(x);
    
    • 1
    • 2
  3. 第三种情况:把空指针转换成目标类型的空指针

    int *p = static_cast<int *>(NULL);	// 等同于 int *p = NULL;
    Dog *g = static_cast<Dog *>(NULL);	// 等同于 Dog *g = NULL;
    
    • 1
    • 2
  4. 第四种情况:把任何类型的表达式转换成void类型

    int *array = new int[10];	
    void *arr = static_cast<void *>(array);	// 等同与 void *arr = array;
    
    • 1
    • 2

2). reinterpret_cast

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

用法: TYPE b = reinterpret_cast ( a )
TYPE必须是一个指针、引用、算术类型、函数指针.

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


定义一个Animal基类,里面有cry()纯虚函数;再定义两个派生类Cat和Dog,分别重写虚函数。

class Animal {
public:
	virtual void cry() {
		cout << "动物叫!" << endl;
	}
};

class Cat : public Animal {
public:
	void cry() {
		cout << "喵喵喵~" << endl;
	}
};

class Dog : public Animal {
public:
	void cry() {
		cout << "汪汪汪~" << endl;
	}
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  1. 用法一:数值与指针之间的转换

    int *p = reinterpret_cast<int *>(0x666666);
    int var = reinterpret_cast<int>(p);
    
    • 1
    • 2
  2. 用法二:不同类型指针和引用之间的转换

    Dog dog1;
    Animal *a1 = &dog1;
    a1->cry();
    
    // 父类指针对象强转为子类对象
    Dog *dog_1 = reinterpret_cast<Dog *>(a1);
    Dog *dog_2 = static_cast<Dog *>(a1);	// 能用static_cast的地方优先使用static_cast
    dog_1->cry();
    dog_2->cry();
    
    
    //Cat *cat_1 = static_cast<Cat *>(dog_1);	// 不同类型指针转换不能使用static_cast
    Cat *cat_1 = reinterpret_cast<Cat *>(dog_1);	// 将狗指针对象转换为猫指针对象
    cat_1->cry();
    
    
    // 引用之间的转换
    Animal &a2 = dog1;
    Dog &dog2 = reinterpret_cast<Dog &>(a2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

运行结果:
在这里插入图片描述

3). dynamic_cast

动态类型转换

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

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

注意:dynamic_cast在将父类cast到子类时,父类必须要有虚函数一起玩。

简单来说,当你定义一个基类对象,然后将子类对象赋值给它时,然后你使用dynamic_cast转换为该子类对象,这样是没问题的,如果转换为另一个子类对象,如果是指针,则为NULL;如果是引用则发生异常。


定义一个Animal虚基类,里面有cry()虚函数;再定义两个派生类Cat和Dog,分别重写虚函数。
再定义两个重载函数,用于类型转换例子演示:

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;
	}
};


void PlayAnimal(Animal *animal) {
	// 如果传入的参数是Dog类型,那么可以转换成功,否则为NULL
	Dog *dog = dynamic_cast<Dog *>(animal);

	if (dog) {
		cout << "这是狗,汪汪汪~" << endl;

	} else {
		cout << "这是猫,喵喵喵~" << endl;
	}
}

void PlayAnimal(Animal &animal) {

	try {
		// 转换引用,如果失败则会抛出异常
		Cat &cat = dynamic_cast<Cat &>(animal);

		cout << "这是猫,";
		cat.cry();

	} catch (std::bad_cast bc) {
		Dog &dog = dynamic_cast<Dog &>(animal);
		
		cout << "这是狗,";
		dog.cry();
	}

}
  • 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
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  1. 指针之间父类转子类的转换

    /* 指针间的转换 */	
    Dog *dog1 = new  Dog();
    Animal *a1 = dog1;
    PlayAnimal(a1);		// void PlayAnimal(Animal *animal) 
    
    Cat *cat1 = new Cat();
    Animal *a2 = cat1;
    PlayAnimal(a2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

cout << endl << “华丽的分割线==================================” << endl << endl;

  1. 引用之间父类转子类的转换

    /* 引用之间的转换 */
    Dog dog2;
    PlayAnimal(dog2);	// void PlayAnimal(Animal &animal)
    
    Cat cat2;
    PlayAnimal(cat2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

运行截图:
在这里插入图片描述

4). const_cast

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

简单来说,就是将常量变量转换为普通变量进行修改值;
但是这其中有一个点要注意,这个常量必须是要可以修改的内存,否则转换过程中会报错!


定义一个函数用于转换字符串数组

void demo(const char *p) {
	// 去除const修饰符
	char *p1 = const_cast<char *>(p);
	p1[0] = 'A';

	// 可以直接进行使用
	const_cast<char *>(p)[1] = 'B';

	cout << p1 << endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  1. 常量字符串数组

    const char p[] = "123456";
    demo(p);
    
    • 1
    • 2

    因为他是一个数组,所以里面的值是可以被修改的

  2. 常量字符串不能去掉const修改
    警告:再去掉常量限定字符之前,保证指针所指向的内存能够修改,不能修改则会引起异常

    const char *cp = "12345678";
    char *cp1 = const_cast<char *>(cp);		
    cp1[0] = 'C';	// 会抛异常,报错!!!
    cout << cp1 << endl;
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

  3. 修改指针变量

    int x = 10;
    const int *a = &x;
    int *b = const_cast<int *>(a);
    *b = 20;
    cout << *b << endl;
    
    • 1
    • 2
    • 3
    • 4
    • 5

运行截图:
在这里插入图片描述


三、类型转换使用建议

  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<>(),去除变量的只读属性


四、总结

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

一般情况下,不建议进行类型转换;避免进行类型转换。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/309833
推荐阅读
相关标签
  

闽ICP备14008679号