C++知识点 -- C++的类型转换

C++知识点 – C++的类型转换


一、C语言中的类型转换

void test()
{
    
    
	int i = 0;
	//隐式类型转换(意义相近的类型)
	double d = i;
	printf("%d, %.2f\n", i, d);

	int* p = &i;
	//显式的强制类型转换(意义不相近的类型,但是转换后的值有意义)
	int address = (int)p;
	printf("%x, %d\n", p, address);
}

在这里插入图片描述
在这里插入图片描述
比较符号两边也会发生隐式类型转换;
如果pos == 0,这里end被提升成了无符号整型,当end减到0时,再–end,就会成-1,而对于无符号整型来说,-1就是最大的数;
因此程序进入了死循环;

二、C++的强制类型转换

(1)兼容c的隐式类型转换和强制类型转换;
(2)期望用户使用c++的显式强制类型转换;

1.static_cast

static_cast用于非多态类型的转换,编译器隐式执行的任意类型转换都可用static_cast,但不能用于两个不相关的类型之间转换;(类似于c的隐式类型转换,转换意义相近的类型)

void test()
{
    
    
	double d = 5.35;
	int i = static_cast<int>(d);
	cout << i << endl;
}

2.reinterpret_cast

reinterpret_cast通常用于将一种类型转换为另一种不同的类型;(类似于c的强制类型转换,类型不同但转换后的值有意义)

void test()
{
    
    
	double d = 5.35;
	int i = static_cast<int>(d);
	cout << i << endl;

	int* p = reinterpret_cast<int*>(i);
}

3.const_cast

const_cast最常用的就是删除变量的const属性,方便赋值;
c++中的const对象并没有存在常量区,而是存在栈上,所以叫常变量,能够通过这种方式修改

void test()
{
    
    
	const int a = 2;
	int* p = const_cast<int*>(&a);
	(*p)++;

	cout << a << endl;
	cout << *p << endl;
}

以上代码的输出结果其实是:
在这里插入图片描述
但是a在实际的存储空间上还是被改变了的;
在这里插入图片描述
原因就在于编译器对于const类型的变量有优化,认为const变量不会被修改;
直接在a初始化的时候就把它放进一个寄存器中,读取的时候不用在内存中取,而是直接去寄存器中取,所以还是2
但是*p实是在内存中取的,所以是3;

给a加上volatitle关键字表示不去优化这个变量;

void test()
{
    
    
	volatile const int a = 2;
	int* p = const_cast<int*>(&a);
	(*p)++;

	cout << a << endl;
	cout << *p << endl;
}

在这里插入图片描述
输出结果a就变为3了;

4.dynamic_cast

dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针/引用(动态转换);

向上转型:子类对象指针/引用 -> 父类对象指针/引用(不需要转换,赋值兼容)
向下转型:父类对象指针/引用 -> 子类对象指针/引用(用dynamic_cast转换是安全的)

注意:
(1)dynamic_cast只能用于父类含有虚函数的类;
(2)dynamic_cast会事先检查转换是否成功,如果能成功就转换,不能就返回0;

class A
{
    
    
public:
	virtual void f(){
    
    }
public:
	int _a = 0;
};

class B : public A
{
    
    
public:
	int _b = 1;
};


void func(A* pa)
{
    
    
	B* pb = (B*)pa;
	pb->_a++;
	pb->_b++;
}

A*是父类指针,可能指向父类对象,也可能指向子类对象;但是指向子类对象无法访问子类独有的成员;
如果使用C中的强制类型转换,会发生越界

class A
{
    
    
public:
	virtual void f(){
    
    }
public:
	int _a = 0;
};

class B : public A
{
    
    
public:
	int _b = 1;
};


void func(A* pa)
{
    
    
	//如果pa指向子类,那么可以转换,转换表达式返回正确的地址
	//如果pa指向父类,那么不可以转换,转换表达式返回nullptr

	B* pb = dynamic_cast<B*>(pa); // 安全的
	if (pb)
	{
    
    
		cout << "转换成功" << endl;
		pb->_a++;
		pb->_b++;
		cout << pb->_a << ":" << pb->_b << endl;
	}
	else
	{
    
    
		cout << "转换失败" << endl;
		pb->_a++;
		cout << pb->_a << endl;
	}

}

void test()
{
    
    
	B b;
	func(&b);
}

使用dynamic_cast转换是安全的;
如果pa指向子类,那么可以转换,转换表达式返回正确的地址;
如果pa指向父类,那么不可以转换,转换表达式返回nullptr;

在这里插入图片描述

例:
在这里插入图片描述
在这里插入图片描述
强制类型转换之后,ptr2指向的地址会改变,变成子类的地址,与dynamic_cast是一样的

猜你喜欢

转载自blog.csdn.net/kissland96166/article/details/130585887