C++强制类型转换

文章目录

  • C语言的强制类型转换----可读性差,十分坑人
  • const_cast----删除const属性的转换
  • dynamic_cast----运行时类型识别(仅用于多态场景)
  • static_cast ----相关类型转换
  • reinterpret_cast----不相关类型转换
  • 拓展1):explicit关键字
  • 拓展 2)类型提升

C语言的强制类型转换----可读性差,十分坑人

先看个笔试选择常考题,看下面代码,写出运行结果:

#include
using namespace std;
int main()
{
	const int a = 10;
	int*p =(int*) &a;
	*p = 20;
	cout << a << endl;
	return 0;
}

C++强制类型转换_第1张图片
输出结果是仍然是10,但是内存中已经是修改后的20。What fuck?事实胜于雄辩,我们知道在C++中被const修饰的变量就是常量,所以,这里显示使用了C语言的强制类型转换,达成了修改意愿。

C语言的中强制类型转换分为隐式类型转换和显示的强制类型转换

直接看栗子

#include
using namespace std;
int main()
{
	int a = 10;
	double b = 20;
	b = a;
	cout << a << endl << b << endl;
	system("pause");
	return 0;
}

C++强制类型转换_第2张图片
int类型的a赋值给double类型的b,是允许的,语法上认为,它们都是相近类型,都是表示数值,所以允许它们直接隐式类型转换。

如果你想把不相近类型强制转换,也许显示调用强制类型转换会有效果。

#include
#include
using namespace std;
int main()
{
	int a = 10;
	int*p = &a;

	int b = (int)p;//把指针类型转换成整形
	system("pause");
	return 0;
}

简单了解了C语言的类型转换,我们再来看看这个题。既然强制类型转换了,为什么输出结果还是10呢?因为const,C++中,编译器认为const修饰的值是常量,所以它会将这个常量放在寄存器中,当需要使用时候,它就从寄存器直接取出来这个初始化时候的常量。
C++强制类型转换_第3张图片
还真是这样,为了让这货好好干活,别再偷懒优化。我们可以在a变量前加volatile,让它每次用a的值都去内存中取,保证a值得内存可见性。
C++强制类型转换_第4张图片

const_cast----删除const属性的转换

const_cast最常用的用途就是删除变量的const属性,简单明了,不用考虑太多。
C++强制类型转换_第5张图片

dynamic_cast----运行时类型识别(仅用于多态场景)

dynamic_cast用于将一个父类对象的指针转换为子类对象的指针或引用(动态转换)。在多态中,我们知道,子类对象、指针、引用都可以用父类对象或者指针去接收,这由语法自动完成切片。不太懂的可以看看这里。https://blog.csdn.net/Vickers_xiaowei/article/details/82750286#_98

向上转型:子类对象指针->父类指针/引用(不需要转换,自动完成切片)
向下转型:父类对象指针->子类指针/引用(用dynamic_cast转型是安全的)

  1. dynamic_cast只能用于含有虚函数的类
  2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0
#include
using namespace std;

class Person{
protected:
	string _name;
	virtual void Print()
	{
		cout << "I am the father" << endl;
	}
};

class Student :public Person
{
public:
	int _num;
	virtual void Print()
	{
		cout << "I am the son" << endl;
	}
};
void Func(Person* p)
{
	//父类对象指针->子类指针/引用
	Student* sp = dynamic_cast<Student*>(p);//只允许子类对象指针转换
	sp->Print();
}
int main()
{
	Person p;
	Student s;
	//Func(&p);//使用dynamic_cast,不能将父类指针转换成子类指针,防止了越界行为
	Func(&s);
	system("pause");
	return 0;
}

涉及多态的类型转换最好使用dynamic_cast,防止越界。

static_cast ----相关类型转换

static_cast用于非多态类型的转换(静态转换) ,任何标准转换都可以用它,但它 不能用于两个不相关的类型进行转换。 这里所谓的相关类型和C语言中可以隐式转换的相近类型概念基本一样,C++使用static_cast更加明显,增强了可读性。

#include
using namespace std;
int main()
{
	int a = 10;
	int*p = static_cast<int*>(&a);
	*p = 20;
	cout << a << endl;
	system("pause");
	return 0;
}

reinterpret_cast----不相关类型转换

reinterpret_cast操作符用于将一种类型转换为另一种不同的类型。与C语言的强制转换可读性更好。

#include
#include
using namespace std;
int main()
{
	int a = 10;
	int*p = &a;

	int b = reinterpret_cast<int>(p);
	system("pause");
	return 0;
}

少用类型转换,多使用C++标准的强制转换

拓展1):explicit关键字

对于单参数构造函数会将单参数隐式类型转换。

#include
using namespace std;

class A
{
public:
	A(int a)
	{
		cout << "A(int a)" << endl;
	}
	A(const A& a)
	{
		cout << "A(const A& a)" << endl;
	}
private:
	int _a;
};

int main()
{
	A a1(1);
	// 隐式转换-> A tmp(1); A a2(tmp);
	A a2 = 1;
	system("pause");
}

上述代码将int类型隐式转换成了自定义类型A,如果不想让这样的隐式类型转换,对于单参数类型转换,explicit关键字阻止经过转换构造函数进行的隐式转换的发生。
C++强制类型转换_第6张图片

拓展 2)类型提升

#include
using namespace std;

int main()
{
	size_t pos = 0;
	int end= 3;
	while (end >= pos)
		--end;
	system("pause");
	return 0;
}

int类型的end与size_t类型的pos在比较时候,会将end的int类型提升到size_t,类型提升总是提升到范围大的那一个,所以上面无符号的-1比0大,上面代码会陷入死循环。

你可能感兴趣的:(C++)