1、const_cast
const_cast用来帮助调用那些应该使用却没有使用const关键字的函数。即在特殊情况下降限制为const成员函数的const定义解除,使其能更改特定属性。
代码示例:
#include <iostream>
struct type {
int i;
type(): i(3) {
}
void f(int v) const {
// this->i = v; // compile error: this is a pointer to const
const_cast<type*>(this)->i = v; // OK as long as the type object isn't const
}
};
int main()
{
int i = 3; // i is not declared const
const int& rci = i;
const_cast<int&>(rci) = 4; // OK: modifies i
std::cout << "i = " << i << '\n';
type t; // if this was const type t, then t.f(4) would be undefined behavior
t.f(4);
std::cout << "type::i = " << t.i << '\n';
const int j = 3; // j is declared const
int* pj = const_cast<int*>(&j);
// *pj = 4; // undefined behavior
void (type::* pmf)(int) const = &type::f; // pointer to member function
// const_cast<void(type::*)(int)>(pmf); // compile error: const_cast does
// not work on function pointers
}
输出:
i = 4
type::i = 4
2、dynamic_cast
如果启动了支持运行时间类型信息(RTTI),dynamic_cast可以有助于判断在运行时所指向对象的确切信息。它与typeid运算符有关。可以将一个基类的指针指向许多不同的子类型(派生类),然后将被转型为基础类的对象还原成原来的类。不过,限于对象指针的类型转换,而非对象变量。
代码示例:
#include <iostream>
struct V {
virtual void f() {
} // must be polymorphic to use runtime-checked dynamic_cast
};
struct A : virtual V {
};
struct B : virtual V {
B(V* v, A* a) {
// casts during construction (see the call in the constructor of D below)
dynamic_cast<B*>(v); // well-defined: v of type V*, V base of B, results in B*
dynamic_cast<B*>(a); // undefined behavior: a has type A*, A not a base of 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; // the most derived object
A& a = d; // upcast, dynamic_cast may be used, but unnecessary
D& new_d = dynamic_cast<D&>(a); // downcast
B& new_b = dynamic_cast<B&>(a); // sidecast
Base* b1 = new Base;
if(Derived* d = dynamic_cast<Derived*>(b1))
{
std::cout << "downcast from b1 to d successful\n";
d->name(); // safe to call
}
Base* b2 = new Derived;
if(Derived* d = dynamic_cast<Derived*>(b2))
{
std::cout << "downcast from b2 to d successful\n";
d->name(); // safe to call
}
delete b1;
delete b2;
}
输出:
downcast from b2 to d successful
3、reinterpret_cast
用于将一个指针转换成其他类型的指针,新类型的指针与旧指针可以毫不相关。通常用于某些非标准的指针数据类型转换,例如将void转换为char。它也可以用在指针和整型数之间的类型转换上。注意:它存在潜在的危险,除非有使用它的充分理由,否则就不要使用它。例如,它能够给将一个int类型的指针转换为float类型的指针,但是这样会造成数据无法被准确的读取。
代码示例:
#include <cstdint>
#include <cassert>
#include <iostream>
int f() {
return 42; }
int main()
{
int i = 7;
// pointer to integer and back
std::uintptr_t v1 = reinterpret_cast<std::uintptr_t>(&i); // static_cast is an error
std::cout << "The value of &i is 0x" << std::hex << v1 << '\n';
int* p1 = reinterpret_cast<int*>(v1);
assert(p1 == &i);
// pointer to function to another and back
void(*fp1)() = reinterpret_cast<void(*)()>(f);
// fp1(); undefined behavior
int(*fp2)() = reinterpret_cast<int(*)()>(fp1);
std::cout << std::dec << fp2() << '\n'; // safe
// type aliasing through pointer
char* p2 = reinterpret_cast<char*>(&i);
if(p2[0] == '\x7')
std::cout << "This system is little-endian\n";
else
std::cout << "This system is big-endian\n";
// type aliasing through reference
reinterpret_cast<unsigned int&>(i) = 42;
std::cout << i << '\n';
[[maybe_unused]] const int &const_iref = i;
//int &iref = reinterpret_cast<int&>(const_iref); //compiler error - can't get rid of const
//Must use const_cast instead: int &iref = const_cast<int&>(const_iref);
}
可能的输出:
The value of &i is 0x7fffdd756f4c
42
This system is little-endian
42
4、static_cast
static_cast能够在相关的对象和指针类型之间进行类型转换。有关的类之间必须通过继承、构造函数或者转换函数发生联系。static_cast操作符还能在数字(原始的)类型之间进行类型转换。通常情况下,static_cast操作符大多数用于将数域宽度较大的类型转换为较小的类型。当转换的类型是原始数据类型时,这种操作可以有效地禁止编译器发出警告。
代码示例:
#include <vector>
#include <iostream>
struct B {
int m = 0;
void hello() const {
std::cout << "Hello world, this is B!\n";
}
};
struct D : B {
void hello() const {
std::cout << "Hello world, this is D!\n";
}
};
enum class E {
ONE = 1, TWO, THREE };
enum EU {
ONE = 1, TWO, THREE };
int main()
{
// 1: initializing conversion
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';
// 2: static downcast
D d;
B& br = d; // upcast via implicit conversion
br.hello();
D& another_d = static_cast<D&>(br); // downcast
another_d.hello();
// 3: lvalue to xvalue
std::vector<int> v2 = static_cast<std::vector<int>&&>(v);
std::cout << "after move, v.size() = " << v.size() << '\n';
// 4: discarded-value expression
static_cast<void>(v2.size());
// 5. inverse of implicit conversion
void* nv = &n;
int* ni = static_cast<int*>(nv);
std::cout << "*ni = " << *ni << '\n';
// 6. array-to-pointer followed by upcast
D a[10];
B* dp = static_cast<B*>(a);
// 7. scoped enum to int or float
E e = E::ONE;
int one = static_cast<int>(e);
std::cout << one << '\n';
// 8. int to enum, enum to another enum
E e2 = static_cast<E>(one);
EU eu = static_cast<EU>(e2);
// 9. pointer to member upcast
int D::*pm = &D::m;
std::cout << br.*static_cast<int B::*>(pm) << '\n';
// 10. void* to any type
void* voidp = &e;
std::vector<int>* p = static_cast<std::vector<int>*>(voidp);
}
输出:
n = 3
v.size() = 10
Hello world, this is B!
Hello world, this is D!
after move, v.size() = 0
*ni = 3
1
0
参考:
1、《C和C++程序员面试秘籍》
2、 https://en.cppreference.com/
谢谢阅读