C++基础 强制转换
目录
static_cast:static_cast(expression)
const_cast
dynamic_cast
reinterpret_cast
C++ 提供以下几类转换
static_cast:static_cast<type-id>(expression)
tatic_cast 主要用于以下几种情况:
- 用于显式地将一个表达式转换为另一种类型,包括基本类型、指针类型和引用类型。
- 用于将基类指针或引用转换为派生类指针或引用(向下转型)。
- 用于将 void* 指针转换为任意类型的指针。
- 用于将任意类型的指针转换为 void* 指针。
需要注意的是tatic_cast 不会在运行时检查该对象的运行时类型,安全的向下转换可以用dynamic_cast
执行
示例
#include <vector>
#include <iostream>struct B
{int m = 0;void hello() const{std::cout << "Hello world,这里是 B!\n";}
};struct D : B
{void hello() const{std::cout << "Hello world,这里是 D!\n";}
};enum class E { ONE = 1, TWO, THREE };
enum EU { ONE = 1, TWO, THREE };int main()
{// 1: 静态向下转型D d;B& br = d; // 通过隐式转换向上转型br.hello();D& another_d = static_cast<D&>(br); // 向下转型another_d.hello();// 2: 左值到右值std::vector<int> v2 = static_cast<std::vector<int>&&>(v);std::cout << "移动后,v.size() = " << v.size() << '\n';// 3: 初始化转换int n = static_cast<int>(3.14); std::cout << "n = " << n << '\n';std::vector<int> v = static_cast<std::vector<int>>(10);std::cout << "v.size() = " << v.size() << '\n';// 4: 弃值表达式static_cast<void>(v2.size());// 5. 隐式转换的逆转换void* nv = &n;int* ni = static_cast<int*>(nv);std::cout << "*ni = " << *ni << '\n';// 6. 数组到指针后随向上转型D a[10];B* dp = static_cast<B*>(a);// 7. 有作用域枚举到 int 或 floatE e = E::ONE;int one = static_cast<int>(e);std::cout << one << '\n';// 8. int 到枚举,枚举到另一枚举E e2 = static_cast<E>(one);EU eu = static_cast<EU>(e2);// 9. 指向成员指针向上转型int D::*pm = &D::m;std::cout << br.*static_cast<int B::*>(pm) << '\n';// 10. void* 到任何类型void* voidp = &e;std::vector<int>* p = static_cast<std::vector<int>*>(voidp);
}
输出
Hello world,这里是 B! Hello world,这里是 D! 移动后,v.size() = 0 n = 3 v.size() = 10 *ni = 3 1 0
const_cast
类型转换运算符,可以将 const 和 volatile 限定符从指针或引用类型中去除。它可以用于将常量对象变成非常量对象,从而允许对其进行修改,函数指针和成员函数指针无法用于 const_cast
示例
#include <iostream>struct type
{int i;type(): i(3) {}void f(int v) const {// this->i = v; // 编译错误:this 是指向 const 的指针const_cast<type*>(this)->i = v; // 只要该对象不是 const 就 OK}
};int main()
{int i = 3; // 不声明 i 为 constconst int& rci = i; const_cast<int&>(rci) = 4; // OK:修改 istd::cout << "i = " << i << '\n';type t; // 如果这是 const type t,那么 t.f(4) 会是未定义行为t.f(4);std::cout << "type::i = " << t.i << '\n';const int j = 3; // 声明 j 为 const[[maybe_unused]] //可能是有意不使用,编译器不会发出警告int* pj = const_cast<int*>(&j);// *pj = 4; // 未定义行为[[maybe_unused]]void (type::* pmf)(int) const = &type::f; // 指向成员函数的指针// const_cast<void(type::*)(int)>(pmf); // 编译错误:const_cast 不能用于成员函数指针
}
dynamic_cast
沿继承层级向上、向下及侧向,安全地转换到其他类的指针和引用,失败会返回空指针
#include <iostream>struct V
{virtual void f() {} // 必须为多态以使用运行时检查的 dynamic_cast
};struct A : virtual V {};struct B : virtual V
{B(V* v, A* a){// 构造中转型(见后述 D 的构造函数中的调用)dynamic_cast<B*>(v); // 良好定义:v 有类型 V*,V 是 B 的基类,产生 B*dynamic_cast<B*>(a); // 未定义行为:a 有类型 A*,A 不是 B 的基类}
};struct D : A, B
{D() : B(static_cast<A*>(this), this) {}
};struct Base
{virtual ~Base() {}
};struct Derived: Base
{virtual void name() {}
};int main()
{D d; // 最终派生对象A& a = d; // 向上转型,可以用 dynamic_cast,但不是必须的[[maybe_unused]]D& new_d = dynamic_cast<D&>(a); // 向下转型[[maybe_unused]]B& new_b = dynamic_cast<B&>(a); // 侧向转型Base* b1 = new Base;if (Derived* d = dynamic_cast<Derived*>(b1); d != nullptr){std::cout << "成功从 b1 向下转型到 d\n";d->name(); // 可以安全调用}Base* b2 = new Derived;if (Derived* d = dynamic_cast<Derived*>(b2); d != nullptr){std::cout << "成功从 b2 向下转型到 d\n";d->name(); // 可以安全调用}delete b1;delete b2;
}
reinterpret_cast
重新解释底层位模式在类型间任意转换,实际上转换比static_cast更不安全,
static_cast就是利用C++类型之间的继承关系图和聚合关系图(编译器必须知道),根据一个子对象地址计算另一个子对象的地址。
reinterpret_cast不关心继承关系,直接把数据类型A的地址解释成另一个数据类型B的地址
示例
#include <cstdint>
#include <cassert>
#include <iostream>int f() { return 42; }int main()
{int i = 7;// 指针到整数并转回std::uintptr_t v1 = reinterpret_cast<std::uintptr_t>(&i); // 不能误用 static_caststd::cout << "&i 的值是 " << std::showbase << std::hex << v1 << '\n';int* p1 = reinterpret_cast<int*>(v1);assert(p1 == &i);// 到另一函数指针并转回void(*fp1)() = reinterpret_cast<void(*)()>(f);// fp1(); 未定义行为int(*fp2)() = reinterpret_cast<int(*)()>(fp1);std::cout << std::dec << fp2() << '\n'; // 安全// 通过指针的类型别名化char* p2 = reinterpret_cast<char*>(&i);std::cout << (p2[0] == '\x7' ? "本系统是小端的\n": "本系统是大端的\n");// 通过引用的类型别名化reinterpret_cast<unsigned int&>(i) = 42;std::cout << i << '\n';[[maybe_unused]] const int &const_iref = i;// int &iref = reinterpret_cast<int&>(const_iref); // 编译错误——不能去除 const// 必须用 const_cast 代替:int &iref = const_cast<int&>(const_iref);
}