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/
謝謝閱讀