c/c++类型转换

发布于:2025-03-01 ⋅ 阅读:(118) ⋅ 点赞:(0)

目录

1、c语言中的类型转换

c++中的类型转换

1、内置类型和自定义类型的隐式转换(借助构造)

2、自定义类型和自定义类型的隐式转换(借助构造)

3、内置类型转自定义类型的隐式转换(重载一个operator 类型)

新增的四种强制类型转换

1、static_cast

2、reinterpret_cast

3、const_cast

4、dynamic_cast

总结:

4、RTTI

重点:


1、c语言中的类型转换

在c语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接受返回值类型不一致时,就需要发生类型转化。

c语言中有2种类型转换:隐式类型转换、显式类型转换

隐式:编译器在编译阶段自动进行,能赚就转,不能转就编译失败

显示:需要用户自己处理。

1、有一定关联的才可以互相转换
    跟整型搭边的,才可以进行隐式类型转换,如下
    char-整型,浮点数-整型 ,有符合-无符号,这些转换会涉及截断、提升
    截断和提升可以看我另外的文章《关于操作符的内容》
    bool和整形 bool和指针(指针为空指针就是0,0就是假,非空指针就是非0,非0就是真)
    

2、指针和整型,有一定关联,指针本身也是数字编号
    所以虽然不能隐式类型转换,但强制的、显式的转换是可行的

3、不同类型之间可以借用指针进行强制转换
    比如h1是个自定义对象,我们如果只想要这个对象的前4个字节
    arc *p1=&h1;
    int* x=(int*)p1;
    这样就可以把指针强制转换类型,然后就可以访问前4个字节(int占4字节)。

int main()
{


	int a1 = 1;
	//隐式
	double a2 = a1;
	printf("%d,%.2f\n", a1, a2);
	
	int* p = &a1;
	//显式
	int ad = (int)p;
	printf("%x,%d\n", p, ad);
	return 0;
}

缺陷:隐式类型转换,可能出现精度丢失的问题(如double-int)

显式转换把所有情况都混合在一起,代码不清晰

比如无符号无法小于0,导致无符号与无符号比较时,可能出现死循环等问题

又比如int跟size_t比较,int会隐式转换成size_t,而负数的int也会照样转,所以还是会出问题。

size_t x=0;
size_t a=10;
while(a>=x)
{
    cout<<a<<endl;
    x--;
}
//会死循环

size_t x=0;
int a=10;
while(a>=x)
{
    cout<<a<<endl;
    x--;
}

//会死循环

c++中的类型转换

 c++是兼容c的,所以c的也能用,c++只是较于c新增了一些内容。

1、内置类型和自定义类型的隐式转换(借助构造)

string s = "231213";
//单参数的构造函数,支持内置类型隐式转换成自定义类型。

上面就是将const char*通过隐式类型转换,在编译器不优化的情况下:先用const char*构造一个临时的string对象,再调用s的拷贝构造,把这个临时对象拷贝给s。优化之后就是直接用const char*构造s。

2、自定义类型和自定义类型的隐式转换(借助构造)

比如vector增加的initializer_list参数的构造函数,stack<pair<int,int>>,都是把一个自定义对象作为构造的参数之一,来构造一个新的自定义对象。

3、内置类型转自定义类型的隐式转换(重载一个operator 类型)

class pl {
public:
    //特殊写法,不要加返回值,否则会跟仿函数冲突
	operator int() {
		return x1 * x2;
	}
private:
	int x1 = 1, x2 = 2;
};

int main()
{
	pl x3;
	//int a = (int)x3;也可以
	int a = x3;
	
	cout << a << endl;
	return 0;
}

新增的四种强制类型转换

1、static_cast

用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast,但不能用于两个不相关的类型进行转换。

int main()
{
	float x = 10.10;
	int f = static_cast<int>(x);
	cout << f << endl;
	//10
	return 0;
}

2、reinterpret_cast

通常为操作数的位模式提供较低层次的重新解释,比如指针。对应c语言的强制类型转换

int main()
{
	int a = 10;
	//int* p = static_cast<int*>(a);会报错,因为指针必须用强转
	int* p = reinterpret_cast<int*>(&a);
	return 0;
}

3、const_cast

const_cast最常用的用途就是删除变量的const属性,方便赋值,但本身也是强制类型转换,只是单独的把去const的功能拎出来,并且提醒const有一定编译器优化的风险,具体看下面。

int main()
{
	const int a = 10;

	int* p = const_cast<int*>(&a);
	*p = 10;
	return 0;
}

这个要注意一个坑

int main()
{
	const int a = 10;
	int* p = const_cast<int*>(&a);
	*p = 5;
	cout << a << endl;
	//10
	cout << (*p) << endl;
	//5
	return 0;
}

因为编译器的优化,导致对于这些const修饰的变量会复制一份到寄存器,而p接受的地址,是a变量的内存的地址,虽然修改成了5,也只是改了在内存的那一份,而寄存器的仍旧是10

如果用监视窗口查看,会发现在监视窗口a已经被改成了5,因为监视窗口针对的是内存。

为此,我们可以a加个修饰  volatile const int a   加了这个修饰,就不会复制一份到寄存器

4、dynamic_cast

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

向上转型:子类对象指针/引用 -》父类指针/引用(不需要转换,直接切片拷贝过去,是遵循继承的赋值兼容规则的)

向下转型:父类对象指针/引用-》子类指针/引用(用dynamic_cast转型是安全的)

因为子类对象可能会有新的成员,而如果利用赋值兼容,把父类对象给了子类指针,那么子类指针访问子类的新的成员,会有越界的风险问题。

注意事项:

1、dynamic_cast只用于父类含有虚函数的类。

2、dynamic_cast会先检查是否能转化成功,能成功则转换,不成功返回0。

class F {
public:
	virtual void f() {

	}
};
class X :public F
{
	
};
void fun(F* pa)
{
	//有风险
	//X* pb = (X*)pa;
	X* pb = dynamic_cast<X*>(pa);
	if (pb)
	{
		cout << "成功" << endl;
	}
	else
	{
		cout << "失败" << endl;
	}
}
int main()
{
	F a;
	X b;
	fun(&a);
	//失败
	fun(&b);
	//成功
	return 0;
}

总结:

强制类型转换关闭或者说是挂起了正常的类型检查,每次使用强转前,先想想能不能不转也达到目的,如果非转不可,就限制转换出来的值的作用域,减少发生错误的概率。

4、RTTI

 RTTI:Run-time Type identification 的简称,即:运行时类型识别

c++通过以下方式支持RTTI:

typeid、dynamic_cast、decltype

重点:

 c++新增的4种强制类型转换是什么

这几个转换的应用场景是什么


网站公告

今日签到

点亮在社区的每一天
去签到