C/C++ 类型转换

Posted cpp_learner

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}

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

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. 第一种情况:父子类之间的类型转换

    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);			// 父类的应用转型到子类的引用
    
  2. 第二种情况:基本类型的转换

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

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

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

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. 用法一:数值与指针之间的转换

    int *p = reinterpret_cast<int *>(0x666666);
    int var = reinterpret_cast<int>(p);
    
  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);
    

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

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. 指针之间父类转子类的转换

    /* 指针间的转换 */	
    Dog *dog1 = new  Dog();
    Animal *a1 = dog1;
    PlayAnimal(a1);		// void PlayAnimal(Animal *animal) 
    
    Cat *cat1 = new Cat();
    Animal *a2 = cat1;
    PlayAnimal(a2);
    

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

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

    /* 引用之间的转换 */
    Dog dog2;
    PlayAnimal(dog2);	// void PlayAnimal(Animal &animal)
    
    Cat cat2;
    PlayAnimal(cat2);
    

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

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. 常量字符串数组

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

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

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

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

    在这里插入图片描述

  3. 修改指针变量

    int x = 10;
    const int *a = &x;
    int *b = const_cast<int *>(a);
    *b = 20;
    cout << *b << endl;
    

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


三、类型转换使用建议

  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/C++ 类型转换的主要内容,如果未能解决你的问题,请参考以下文章

c/c++一个关于char类型转换的c语言代码示例

c/c++一个关于char类型转换的c语言代码示例

c/c++一个关于char类型转换的c语言代码示例

为 Blogger 上的博客格式化代码片段 [关闭]

[linux][c/c++]代码片段01

[linux][c/c++]代码片段02