typeid
- typeid
typeid是C++标准库中提供的一种运算符,它用于获取类型的信息。它主要用于类型检查和动态类型识别。当你对一个变量或对象使用typeid运算符时,它会返回一个指向std::type_info类型的指针,这个信息包含了关于该类型名称、大小、基本成员等元数据。
(1)typeid是一个运算符,类似于sizeof
(2)typeid定义在头文件typeinfo中,必须包含该头文件
(3)typeid用来返回一个变量(表达式)(对象)的类型
(4)typeid使用实战
#include <typeinfo>
int main() {
int a; // a type:i
cout << "a type:" << typeid(a).name() << endl;
char a1; // a1 type:c
cout << "a1 type:" << typeid(a1).name() << endl;
uint8_t a2; // a2 type:h
cout << "a2 type:" << typeid(a2).name() << endl;
unsigned char a3; // a3 type:h
cout << "a3 type:" << typeid(a3).name() << endl;
signed char a4; // a4 type:a
cout << "a4 type:" << typeid(a4).name() << endl;
return 0;
}
- typeid的深层次说明
(1)一个表达式的类型分静态类型和动态类型,分别对应编译期和运行时类型决策系统
(2)typeid可用来返回静态类型,也可用来返回动态类型
(3)typeid是C++语言本身的特性,由编译器和库函数共同支撑
(4)typeid真正大用在引入class和继承后,并结合指针和引用后才能显现出来
4种cast转换
- static_cast
static_cast 用于在类型之间进行标准转换,如基本类型转换、类层次结构之间的向上和向下转换,以及隐式转换。
(1)源生类型之间的隐式类型转换,可以用static_cast来明确告知编译器,避免警告,转换后可能丢失精度,正确性需要程序员自己保证
(2)用来将void *p转为具体的指针类型,取回原有的指针类型
(3)用于类层次结构中父类和子类之间指针和引用的转换。其中上行转换时安全的,而下行转换时不安全的。
(4)总结:static_cast<>()是编译时静态类型检查,使用static_cast可以尽量发挥编译器的静态类型检查功能,但是并不能保证代码一定“正确”(譬如可能会丢失精度导致错误,可能经过void *之后导致指针类型错误,可能下行转换导致访问错误。)
(5)评价:static_cast必须会用,见了必须认识,能理解使用static_cast的意义,但是实际上只能解决很初级的编程问题,属于初级语法特性。
class Base {
public:
virtual void show() { std::cout << "Base class" << std::endl; }
};
class Derived : public Base {
public:
void show() override { std::cout << "Derived class" << std::endl; }
};
int test() {
// 基本类型转换
int a = 10;
double b = static_cast<double>(a);
std::cout << "a: " << a << ", b: " << b << std::endl;
int *p = &a;
void *p1 = p; p1已经丢掉了自己的类型
int *p2 = static_cast<int *>(p1); // p2又取回了自己的类型
// std::cout << "*p1: " << *p1 << std::endl;//error: ‘void*’ is not a
// pointer-to-object type
int *p3 = (int *)p1;
std::cout << "*p3: " << *p3 << std::endl;
std::cout << "*p2: " << *p2 << std::endl;
// 类层次结构转换 类层次结构之间的向上和向下转换
Base *basePtr = new Derived();
Derived *derivedPtr = static_cast<Derived *>(basePtr);
derivedPtr->show(); // 输出 "Derived class"
delete basePtr;
return 0;
}
-
reintepret_cast
reinterpret_cast 用于将指针或引用类型转换为其他指针或引用类型。它通常用于底层的、与类型无关的编程,需要谨慎使用。
(1)用于明确告知编译器该类型转换在编译时放行,正确性由程序员自己负责
(2)reintepret_cast转换前后对象的二进制未发生任何变化,只是对这些二进制位的编译器类型标识发生了变化,或者说是编译器看待这些二进制位的结论不同了
(3)reintepret_cast一般用于将指针转成int或者回转,将A类型指针转为B类型指针等
(4)reintepret_cast其实就是让C++在本次转换中放弃严苛的编译器类型检查 -
const_cast
const_cast 用于在类型中添加或移除 const 属性。它常用于需要修改常量数据的场景。
(1)用来修改类型的const或volatile属性
(2)格式为:const_cast<type_id> (expression)
(3)思考:const_cast为什么能修改const为非const?
#include <iostream>
void modifyValue(const int* ptr) {
int* modifiablePtr = const_cast<int*>(ptr);
*modifiablePtr = 20;
}
int main() {
const int value = 10;
std::cout << "Before modification: " << value << std::endl;
modifyValue(&value);
std::cout << "After modification: " << value << std::endl; // 输出结果是未定义的行为
return 0;
}
- dynamic_cast
dynamic_cast 用于在类层次结构中进行安全的向下转换,前提是类必须有虚函数。它在运行时进行类型检查,失败时返回 nullptr。
(1)只用在父子class的指针和引用访问时的转换中,尤其是下行转换时
(2)属于一种运行时转换机制,运行时才能知道转换结果是NULL还是有效对象
(3)运行时确定对象类型RTTI(run time type indentification)是一种需求,C++有一套机制来实现
#include <iostream>
class Base {
public:
virtual void show() {
std::cout << "Base class" << std::endl;
}
};
class Derived : public Base {
public:
void show() override {
std::cout << "Derived class" << std::endl;
}
};
int main() {
Base* basePtr = new Derived();
Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);
if (derivedPtr) {
derivedPtr->show(); // 输出 "Derived class"
} else {
std::cout << "dynamic_cast failed" << std::endl;
}
delete basePtr;
return 0;
}
- 4种cast转换总结
(1)C中一般都用隐式转换或强制类型转换解决,本质上是一种一刀切方案,全靠程序员自己把控
(2)C++中4种cast转换实际上是细分了具体场景,让程序员在具体情况下显式的使用相应的cast来转换,让编译器和运行时尽可能帮程序员把关。
总结
了解typeid的使用方法
认识4种cast转换,会简单使用
学习记录,侵权联系删除。
来源:朱老师物联网大课堂