下载asp做网站自动秒收录网
一、C语言中的类型转化
在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与
接收返回值类型不一致时,就需要发生类型转化,C语言中总共有两种形式的类型转换:隐式类型
转换和显式类型转换。
1. 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败
2. 显式类型转化:需要用户自己处理
char a = 10, b = 20;
int c = a + b; // a和b先提升为int再相加void foo(double d);
foo(10); // 10被转换为double类型int x = 3.14; // x = 3(小数部分被截断)int* p = &i;
// 显示的强制类型转换
int address = (int) p;
缺点:转换的可视性比较差,所有的转换形式都是以一种相同形式书写,难以跟踪错误的转换。
二、C++中的类型转化
1.隐式类型转换
与C语言类似,编译器自动完成,但C++的隐式转换规则更严格,尤其在面向对象编程中。
1. 基本类型的隐式转换
- 遵循C语言的算术提升规则(如
char
→int
→double
)。 - 类类型可以通过构造函数或类型转换运算符隐式转换:
class MyInt { public:MyInt(int x) {} // 允许从int隐式转换为MyInt }; MyInt a = 5; // 隐式调用构造函数
2. 派生类到基类的转换
- 在继承体系中,派生类对象可以隐式转换为基类指针或引用(会切片):
class Base {}; class Derived : public Base {}; Derived d; Base* pb = &d; // 隐式向上转换(Upcasting)
2.显式类型转换(强制转换)
C++提供了四种类型安全的强制转换操作符,取代C风格的强制转换((type)value
),以增强代码可读性和安全性。
1. static_cast
- 用途:用于明确定义的、编译时已知的类型转换。
- 示例:
int main() {double d = 12.34;int a = static_cast<int>(d);cout<<a<<endl;return 0; }
- 限制:
- 不能用于无关类型(如指针和整数之间)。
- 无法去除
const
或volatile
属性。
2. dynamic_cast
- 用途: dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)。向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)。向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)。注意:1. dynamic_cast只能用于父类含有虚函数的类。
2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0。
- 示例:
class A { public:virtual void f() {} }; class B : public A {}; void fun(A* pa) {// dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回B* pb1 = static_cast<B*>(pa);B* pb2 = dynamic_cast<B*>(pa);cout << "pb1:" << pb1 << endl;cout << "pb2:" << pb2 << endl; } int main() {A a;B b;fun(&a);fun(&b);return 0; }
3. const_cast
- 用途:添加或移除
const
属性,常用于删除const属性。 - 示例:
void Test () {const int a = 2;int* p = const_cast<int*>(&a );*p = 3;cout<< a <<endl; }
4. reinterpret_cast
-
用途:低层次的类型重新解释(如指针与整数之间的转换),不进行类型检查,用于将一种类型转换为另一种不同的类型。
- 示例:
int main() {double d = 12.34;int a = static_cast<int>(d);cout << a << endl;// 这里使用static_cast会报错,应该使用reinterpret_cast//int *p = static_cast<int*>(a);int* p = reinterpret_cast<int*>(a);return 0; }
- 风险:可能导致未定义行为,应尽量避免使用。
三、运行时类型识别(RTTI)
我们每个人都有一个身份证,身份证上记录了这个人的姓名、出生日期、性别等信息。在C++中,每个对象也有一个“身份证”,这个“身份证”记录了对象的类型信息。RTTI就像是读取身份证信息的工具,它允许我们在程序运行时查看对象的类型。
1.typeid
操作符
typeid
操作符就像是你查看某个人的身份证,它会返回一个type_info
对象,这个对象包含了类型的信息。
#include <iostream>
#include <typeinfo>class Base {
public:virtual ~Base() {}
};class Derived : public Base {};int main() {Base* basePtr = new Derived();std::cout << "Type of basePtr: " << typeid(*basePtr).name() << std::endl;delete basePtr;return 0;
}
在这个例子中,typeid(*basePtr)
会返回一个type_info
对象,表示basePtr
指向的对象的实际类型。注意,为了使typeid
能够正确工作,基类通常需要至少有一个虚函数(即多态类型)。
2.dynamic_cast
操作符
dynamic_cast
操作符就像是在不同类型的证件之间进行安全转换。它主要用于将基类指针或引用转换为派生类指针或引用,并且只有在转换是安全的情况下才会成功。
#include <iostream>class Base {
public:virtual ~Base() {}
};class Derived : public Base {
public:void derivedFunction() {std::cout << "Derived function called." << std::endl;}
};int main() {Base* basePtr = new Derived();Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);if (derivedPtr) {derivedPtr->derivedFunction();} else {std::cout << "Conversion failed." << std::endl;}delete basePtr;return 0;
}
在这个例子中,dynamic_cast
尝试将basePtr
转换为Derived*
。如果basePtr
实际上指向一个Derived
对象,转换会成功,否则会返回nullptr
。
3. RTTI的缺点
- 性能开销:RTTI会增加程序的运行时开销,特别是在频繁使用的情况下。
- 代码复杂性:过度依赖RTTI可能会使代码变得复杂,难以维护。
4. 适用场景
- 多态类型:RTTI主要用于处理多态类型,即至少有一个虚函数的类。
- 调试和日志:在调试或记录日志时,RTTI可以帮助识别对象的实际类型。
- 动态类型转换:当需要在运行时安全地转换类型时,可以使用
dynamic_cast
。