个人主页:企鹅不叫的博客
专栏
- C语言初阶和进阶
- C项目
- Leetcode刷题
- 初阶数据结构与算法
- C++初阶和进阶
- 《深入理解计算机操作系统》
- 《高质量C/C++编程》
- Linux
⭐️ 博主码云gitee链接:代码仓库地址
⚡若有帮助可以【关注+点赞+收藏】,大家一起进步!
【初阶与进阶C++详解】第一篇:C++入门知识必备
【初阶与进阶C++详解】第二篇:C&&C++互相调用(创建静态库)并保护加密源文件
【初阶与进阶C++详解】第三篇:类和对象上(类和this指针)
【初阶与进阶C++详解】第四篇:类和对象中(类的六个默认成员函数)
【初阶与进阶C++详解】第五篇:类和对象下(构造+static+友元+内部类
【初阶与进阶C++详解】第六篇:C&C++内存管理(动态内存分布+内存管理+new&delete)
【初阶与进阶C++详解】第七篇:模板初阶(泛型编程+函数模板+类模板+模板特化+模板分离编译)
【初阶与进阶C++详解】第八篇:string类(标准库string类+string类模拟实现)
【初阶与进阶C++详解】第九篇:vector(vector接口介绍+vector模拟实现+vector迭代器区间构造/拷贝构造/赋值)
【初阶与进阶C++详解】第十篇:list(list接口介绍和使用+list模拟实现+反向迭代器和迭代器适配)
【初阶与进阶C++详解】第十一篇:stack+queue+priority_queue+deque(仿函数)
【初阶与进阶C++详解】第十二篇:模板进阶(函数模板特化+类模板特化+模板分离编译)
【初阶与进阶C++详解】第十三篇:继承(菱形继承+菱形虚拟继承+组合)
【初阶与进阶C++详解】第十四篇:多态(虚函数+重写(覆盖)+抽象类+单继承和多继承)
【初阶与进阶C++详解】第十五篇:二叉树搜索树(操作+实现+应用KVL+性能+习题)
【初阶与进阶C++详解】第十六篇:AVL树-平衡搜索二叉树(定义+插入+旋转+验证)
【初阶与进阶C++详解】第十七篇:红黑树(插入+验证+查找)
【初阶与进阶C++详解】第十八篇:map_set(map_set使用+multiset_multimap使用+模拟map_set)
【初阶与进阶C++详解】第十九篇:哈希(哈希函数+哈希冲突+哈希表+哈希桶)
【初阶与进阶C++详解】第二十篇:unordered_map和unordered_set(接口使用+模拟实现)
【初阶与进阶C++详解】第二十一篇:哈希应用(位图实现应用+布隆过滤器增删查优缺点+海量数据面试题)
【初阶与进阶C++详解】第二十二篇:C++11新特性(列表初始化+变量类型推到+右值引用+新增默认成员函数+可变模板参数+lambda表达式+包装器function_bind)
【初阶与进阶C++详解】第二十三篇:异常(异常抛出+异常捕获+异常优缺点)
【初阶与进阶C++详解】第二十四篇:智能指针(内存泄漏+RAII+auto_ptr+unique_ptr+shared_ptr+weak_ptr+定制删除器)
在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就需要发生类型转化,C语言中总共有两种形式的类型转换:隐式类型转换和显式类型转换。
- 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败
- 显式类型转化:需要用户自己处理
void Test () { int i = 10; // 隐式类型转换 double d = i; printf("%d, %.3f\n" , i, d); int* ptr = &i; // 显示的强制类型转换 int address = (int) ptr; printf("%x, %d\n" , ptr, address); }
缺陷:
- 隐式类型转化有些情况下可能会出问题:比如数据精度丢失
- 显式类型转换将所有情况混合在一起,代码不够清晰
static_cast用于相近类型之间的类型转换
int main() { double d = 13.14; //静态转换:static_cast //支持任何隐式类型转换 但它不支持两个不相关的类型进行强制转换 int a = static_cast<int>(d); cout<<a<<endl; return 0; }
reinterpret_cast用于不相近类型之间的类型转换
int main () { int i = 10; //强制类型转换:reinterpret_cast //重新解释,用于将一种类型转换为另一种不同的类型 int* pi = &i; int i2 = reinterpret_cast<int> (pi); return 0; }
const_cast常用于删除变量的const属性,即用于将const变量转为非const变量,方便赋值
int main () { const int ci = 10; const int* pci = &ci; int* pci2 = const_cast<int*> (&ci); *pci2 = 20; cout << ci << endl; //10 cout << *pci2 << endl;//20 cout << *pci << endl; //20 cout << "adress" << endl; //下面三个地址都一样 编译器做了优化 cout << &ci << endl; cout << pci2 << endl; cout << pci << endl; return 0; }
dynamic_cast 用于将一个父类对象的指针转换为子类对象的指针或引用(动态转换),只能用于含有虚函数的父类(非多态不能使用dynamic_cast),规范向下转换,会检查是否能转换成功,能成功则转换,不能则返回0
- 向上转型:子类对象指针->父类指针/引用(不需要转换,赋值兼容规则)
- 向下转型:父类对象指针->子类指针/引用(用dynamic_cast转型是安全的)
class A { public: virtual void f(){} }; class B : public A {}; void fun(A* pa) { B* ptr = dynamic_cast<B*>(pa); //用下面这两个转换,A转B,B转B都会成功,但是不安全 //B* ptr = reinterpret_cast(pa); //B* ptr = (B*)pa; if (ptr) { cout << "转换成功" << ptr << endl; } else { cout << "转换失败" << ptr << endl; } } int main() { A a; B b; fun(&a);//转换失败00000000,子类转换成父类,可能导致越界,不安全所以失败 fun(&b);//转换成功(某个地址) return 0; }
explicit关键字阻止经过转换构造函数进行的隐式转换的发生
//explicit class A { public: //explicit会阻止单参构造的隐式类型转换 //编译器报错,不能从int类型转换到A类型 explicit A(int a) :_a(a) { cout << "A(int a) " << endl; } private: int _a; }; int main() { //explicit关键字会阻止单参构造函数进行的隐式转换 A e = 10; return 0; }
RTTI:Run-time Type identification的简称,即:运行时类型识别。
C++通过以下方式来支持RTTI:
- typeid运算符(返回的是类型的字符串typeid(对象).name())
- dynamic_cast运算符
- decltype,获取对象具体类型
- 去const属性用const_cast
- 基本类型转换用static_cast
- 多态类之间的类型转换用dynamic_cast
- 不同类型的指针类型转换用reinterpret_cast
强烈建议:避免使用强制类型转换