Let’s begin with a review of casting syntax, because there are usually
three different ways to write the same cast. C-style casts look like this:
(T) expression | // cast expression to be of type T |
Function-style casts use this syntax: T(expression) | // cast expression to be of type T |
There is no difference in meaning between these forms; it’s purely a
matter of where you put the parentheses. I call these two forms oldstyle casts.
C++ also offers four new cast forms (often called new-style or C++-style
casts):
const_cast<T>(expression)
dynamic_cast<T>(expression)
reinterpret_cast<T>(expression)
static_cast<T>(expression)
Each serves a distinct purpose:
■ const_cast is typically used to cast away the constness of objects. It
is the only C++-style cast that can do this.
■ dynamic_cast is primarily used to perform “safe downcasting,” i.e.,
to determine whether an object is of a particular type in an inheritance hierarchy. It is the only cast that cannot be performed using the old-style syntax. It is also the only cast that may have a
significant runtime cost. (I’ll provide details on this a bit later.)
■ reinterpret_cast is intended for low-level casts that yield implementation-dependent (i.e., unportable) results, e.g., casting a pointer
to an int. Such casts should be rare outside low-level code. I use it
only once in this book, and that’s only when discussing how you
might write a debugging allocator for raw memory (see Item 50).
■ static_cast can be used to force implicit conversions (e.g., non-const
object to const object (as in Item 3), int to double, etc.). It can also be
used to perform the reverse of many such conversions (e.g., void*
pointers to typed pointers, pointer-to-base to pointer-to-derived),
though it cannot cast from const to non-const objects. (Only
const_cast can do that.)
The old-style casts continue to be legal, but the new forms are preferable. First, they’re much easier to identify in code (both for humans
and for tools like grep), thus simplifying the process of finding places
in the code where the type system is being subverted. Second, the
more narrowly specified purpose of each cast makes it possible for
compilers to diagnose usage errors. For example, if you try to cast
away constness using a new-style cast other than const_cast, your
code won’t compile.
用static_cast<*this>()表明类型转换的隐含问题。
转换之后操作的并非原有对象,而是一个副本,是一个临时变量,无法取地址,右值。
class Base
{
public:
Base(int _i) :i(_i)
{}
virtual void onReSize(int _i)
{
i = _i;
}
int i = 0;
};
class Derived : public Base
{
public:
Derived(int _i, int _j):Base(_i), j(_j)
{}
void onReSize(int _i)
{
static_cast<Base>(*this).onReSize(_i);
j = _i * 2;
}
void printSize()
{
std::cout << i << j;
}
int j = 0;
};
int main()
{
Base ba(6);
Derived de(10, 22);
de.onReSize(99);
auto x = dynamic_cast<Base*>(&de);
x->onReSize(88); // 调用扩展类
auto y = dynamic_cast<Base*>(&ba);
y->onReSize(66); // 调用基类,x与y均只有onResize函数
auto z = dynamic_cast<Derived*>(&ba); // z为nullptr
if (z != nullptr)
{
z->onReSize(77);
z->printSize();
}
auto zz = dynamic_cast<Derived*>(&de);
zz->onReSize(99);
zz->printSize();
return 0;
}