文章目录
- C++的类型转换
- C++的4种强制类型转换
- RTTI
C++的类型转换
-
类型转换
-
内置类型之间的转换
// a、内置类型之间 // 1、隐式类型转换 整形之间/整形和浮点数之间 // 2、显示类型的转换 指针和整形、指针之间 int main() { int i = 1; // 隐式类型转换 double d = i; printf("%d, %.2f\n", i, d); int* p = &i; // 显示的强制类型转换 int address = (int)p; printf("%p, %d\n", p, address); return 0; }
-
内置类型与自定义类型之间的类型转换
-
内置类型转自定义类型:通过 自定义类型的 构造函数,使得内置类型可以转换为自定义类型
-
自定义类型转内置类型:通过operator语法来实现 自定义类型转换为 内置类型
operator + 允许类型转换的类型(),该语法比较特殊,不用写返回值,但是函数体有返回值,返回值类型是 允许类型转换的类型 -
样例
// b、内置类型和自定义类型之间 // 1、自定义类型 = 内置类型 ->构造函数支持 // 2、内置类型 = 自定义类型 class A { public: //explicit A(int a) A(int a) :_a1(a) ,_a2(a) {} A(int a1, int a2) :_a1(a1) , _a2(a2) {} // ()被仿函数占用了,不能用 // operator 类型实现,无返回类型 //explicit operator int() //explicit关键字是禁止隐式类型转换,此处是禁止 A 隐式类型转换为 int operator int() { return _a1 + _a2; } private: int _a1 = 1; int _a2 = 1; }; int main() { string s1 = "1111111";//这就是 内置类型 通过 构造函数 隐式类型转化为 string 类型 A aa1 = 1; //A aa1 = (A)1; A aa2 = { 2,2 }; const A& aa3 = { 2,2 }; int z = aa1.operator int(); //int x = (int)aa1; int x = aa1; int y = aa2; cout << x << endl; cout << y << endl; std::shared_ptr<int> foo; std::shared_ptr<int> bar(new int(34)); //if (foo.operator bool()) if (foo) std::cout << "foo points to " << *foo << '\n'; else std::cout << "foo is null\n"; if (bar) std::cout << "bar points to " << *bar << '\n'; else std::cout << "bar is null\n"; return 0; }
-
-
自定义类型与自定义类型之间的类型转换:通过对应的构造函数支持
// c、自定义类型和自定义类型之间 -- 对应的构造函数支持 class A { public: A(int a) :_a1(a) , _a2(a) {} A(int a1, int a2) :_a1(a1) , _a2(a2) {} int get() const { return _a1 + _a2; } private: int _a1 = 1; int _a2 = 1; }; class B { public: B(int b) :_b1(b) {} B(const A& aa) :_b1(aa.get()) {} private: int _b1 = 1; };
-
C++的4种强制类型转换
标准C++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符:static_cast、reinterpret_cast、const_cast、dynamic_cast
-
static_cast
static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用 static_cast,但它不能用于两个不相关的类型进行转换
语法: static_cast<要隐式转为的类型>(被转的变量);
int main() { double d = 12.34; int a = static_cast<int>(d); cout<<a<<endl; return 0; }
-
reinterpret_cast
reinterpret_cast操作符通常为操作数的位模式提供较低层次的重新解释,用于将一种类型转换 为另一种不同的类型。即reinterpret_cast对应强制类型转换,数据的意义已经发生改变
语法: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; }
-
const_cast
const_cast最常用的用途就是删除变量的const属性,方便赋值
对应强制类型转换中有风险的去掉const属性的操作
语法:const_cast<要隐式转为的类型>(被转的变量);
volatile 修饰const变量,表明取变量的值时是去内存中去。 const 变量 正常情况下是被编译器用宏替代的/取值时从寄存器中取的。int main() { // 对应隐式类型转换 -- 数据的意义没有改变 double d = 12.34; int a = static_cast<int>(d); // 对应强制类型转换中有风险的去掉const属性 volatile const int b = 2;//此处如果没有volatile修饰,那么下文打印的b的结果还是2,但是实际上调试等操作可以看到b在内存中的值已经被修改了,那为什么打印出来是2呢?因为vs优化 const变量是直接被宏替代的,这个过程是编译过去中进行的,而改变b的值的操作是运行时进行的。 int* p2 = const_cast<int*>(&b); *p2 = 3; cout << b << endl; cout << *p2 << endl; return 0; }
-
dynamic_cast
dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换) 。 即 dynamic_cast 用于 父类和子类之间的转换
父类和子类之间转换分为两种
**向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则) ** 向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)
dynamic_cast使用的范围:dynamic_cast只能用于父类含有虚函数的类
优点: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);//其实reinterpret_cast也能转换,但是不安全,因为它们不会对其进行检查 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; }
RTTI
- 概念:RTTI是指 运行时类型识别
-
C++通过以下方式来支持RTTI
- typeid运算符:返回字面为数据的类型的字符串。(即int类型转换成"int")
- dynamic_cast运算符
- decltype