(十五)C++进阶之类型转换

1.1、类型转换

所谓的类型转换,就是将一种类型转变为另外一种类型,例如在C语言中常用的指针强制转换 char*p,但是 c 风格的类型转换有不少的缺点,有的时候用 c 风格的转换是不合适的,因为它可以在任意类型之间转换,比如你可以把一个指向const 对象的指针转换 成指向非const 对象的指针,把一个指向基类对象的指针转换成指向一个派生类对象的  指针,这两种转换之间的差别是巨大的,但是传统的 c 语言风格的类型转换没有区分这些。

还有一个缺点就是,c 风格的转换不容易查找,他由一个括号加上一个标识符组成,  而这样的东西在c++程序里一大堆。所以c++为了克服这些缺点,引进了4新的类型转换操作符。

1.2、静态类型转换static_cast

使用格式:在这里插入图片描述

我们来测试一下静态类型转换使用条件:

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>

using namespace std;

class Person
{
public:
	Person()
	{

	}

private:
	int a;
};

class Animal
{
public:
	Animal()
	{

	}

private:
	int a;
};

class Dog :public Animal
{
public:
private:
	int b;
};

int main(void)
{
	char *pc = NULL;
	int *pi = NULL;


	Person *pp = NULL;

	Animal *pa = NULL;

	Dog  *pd = NULL;

	Person p;

	Person &pp1 = p;

	Animal a;

	Animal &aa = a;

	Dog  d;

	Dog &dd = d;

	pi = static_cast<int*>(pc);
	pc = static_cast<char*>(pi);

	pp = static_cast<Person*>(pa);

	pa = static_cast<Animal*>(pd);

	pd = static_cast<Dog*>(pa);

	pp1 = static_cast<Person&>(aa);

	aa = static_cast<Animal&>(dd);

	dd = static_cast<Dog&>(aa);

	return 0;
}



这段代码主要测试整形指针和char类型指针之间的转换,不同类之间的指针和引用,和具有继承关系的类之间的指针和引用。

最终由四个地方编译器报错:
在这里插入图片描述

我们把语法有错误的地方屏蔽运行一下看看是否能运行,运行是没人和问题的,下面我们总结一下。
在这里插入图片描述

也就是说对于 static_cast 而言,指针 int< - >char 是不允许类型转换的,然后不同类之间的指针和引用也是不能够转换的。

唯一能够转换的就是 父类< - >子类的指针和引用,但是这种方式也是有问题的,虽然类型转换没问题,但是我们知道子类指针指向父类,肯定会存在成员之间的访问出错问题,所以建议转换的话只是由父类指向子类。

1.3、dynamic_cast转换

dynamic_cast 是基于子类和父类之间的多态类型转换。
我们看一下这段代码:



#define _CRT_SECURE_NO_WARNINGS

#include <iostream>

using namespace std;


class Animal
{
public:
	Animal()
	{

	}

	virtual void print(void) = 0;

private:
	int a;
};

class Dog :public Animal
{
public:
	virtual void print(void)
	{

	}
private:
	int b;
};

class Cat :public Animal
{
public:
	virtual void print(void)
	{

	}
private:
	int b;
};

int main(void)
{


	Animal *pa = NULL;

	Dog  *pd = NULL;

	Cat *pc = NULL;


	Dog  d;

	Dog &dd = d;

	Cat c;

	Cat &cc = c;


	pa = dynamic_cast<Animal *>(pd);

	pd = dynamic_cast<Dog *>(pa);

	pd = dynamic_cast<Dog *>(pc);


	dd = dynamic_cast<Dog&>(cc);


	return 0;
}

这段代码我们定义一个动物类,里面有一个纯虚函数print,然后创建两个子类dog和cat,分别在那里面进行实现纯虚函数。

编译器并没有提示什么错误,那么我们运行一下看看:
在这里插入图片描述

但是程序运行后,奔溃了,我们调试看看是哪一个语句奔溃的。
在这里插入图片描述
在最后一个引用上,两个对象之间的引用不可进行转换。

我将main函数改为下面的:

int main(void)
{


	Animal *pa = new Cat();

	Dog  *pd = new Dog();

	Cat *pc = new Cat();

	Dog  *pd1 = new Dog();

	Cat *pc2 = new Cat();



	pa = dynamic_cast<Animal *>(pd);

	pa->print();


	pd = dynamic_cast<Dog *>(pa);

	pd->print();

	cout << "--------------------";

	pd1 = dynamic_cast<Dog *>(pc2);

	pd1->print();
	return 0;
}

前面证明两个继承同一个父类的子类,dynamic_cast编译器是不报错,而且也能运行,但是转换后的指针能否执行对应的函数呢?

运行结果如下:
在这里插入图片描述
最终发现虽然能转换,但是却没有输出,是不是他直接返回null了呢?

我们在加一个语句测试一下:
在这里插入图片描述

测试结果:
在这里插入图片描述

果然为null,所以对于使用dynamic_cast的使用,最好判断一下是否转换成功,否则你使用后发现这个很难找到出错的问题。

所以总结一下:dynamic_cast 使用与多态的子父类,他们之间的指针是可以互相进行转换的,但是还是那个问题,不建议子类指针指向父类,否则容易发生访问出错问题。

1.4、const_cast转换

如同他的命名,它的功能是去掉const属性转换,而且目标类类型只能是指针或引用。
如下面这段代码:


#define _CRT_SECURE_NO_WARNINGS

#include <iostream>

using namespace std;


int main(void)
{
	const int a = 0;
	const int *pa = &a;

	int &aa = const_cast<int &>(a);
	aa++;
	cout << aa << endl;

	int *paa = const_cast<int *>(pa);

	(*paa)++;

	cout << (*paa) << endl;
	return 0;
}

运行结果:
在这里插入图片描述
那么这时候a的值是多少呢?其实之前我们了解过,const是直接开辟一个表存储的,所以哪怕去掉const也只是在临时空间开辟一个空间给引用和指针使用而已,所以a是永远不变的。
我们直接输出a的值:
在这里插入图片描述

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

1.5、reinterpret_cast转换

reinterpret_cast 是任何类型都可以转换,包括函数在内,但是权限越大,越是容易出错,我们还是一第一个static_cast这个例子来看一下:


#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

class Person
{
public:
	Person()
	{

	}

private:
	int a;
};

class Animal
{
public:
	Animal()
	{

	}

private:
	int a;
};

class Dog :public Animal
{
public:
private:
	int b;
};

int main(void)
{
	char *pc = NULL;
	int *pi = NULL;


	Person *pp = NULL;

	Animal *pa = NULL;

	Dog  *pd = NULL;

	Person p;

	Person &pp1 = p;

	Animal a;

	Animal &aa = a;

	Dog  d;

	Dog &dd = d;

	pi = reinterpret_cast<int*>(pc);
	pc = reinterpret_cast<char*>(pi);

	pp = reinterpret_cast<Person*>(pa);

	pa = reinterpret_cast<Animal*>(pd);

	pd = reinterpret_cast<Dog*>(pa);

	pp1 = reinterpret_cast<Person&>(aa);

	aa = reinterpret_cast<Animal&>(dd);

	dd = reinterpret_cast<Dog&>(aa);

	

	return 0;
}

在这里插入图片描述

编译器一个都不报错,但是使用这个转化时候一定要考虑清楚是否能够转换,否则跑着跑着程序就奔溃了。

发布了29 篇原创文章 · 获赞 0 · 访问量 406

猜你喜欢

转载自blog.csdn.net/weixin_42547950/article/details/104537363