当转换为完全不同的 class 时,static_cast 会如何表现?
How does static_cast behave when cast to a totally different class?
我正在做一些学习 C++ 中的继承和虚方法的练习。
所以我发现自己喜欢这个:
class A{
public:
virtual void f() const {cout << "A::f";}
virtual void g() {cout << "A::g"; m();}
virtual void h() {cout << "A::h"; f();}
void m() {cout << "A::m"; f();}
virtual A* n() { cout << "A::n"; return this;}
}
class B : public A{
public:
virtual void f() const {cout << "B::f";} //override
void g() {cout << "B::g"; A::n();} //override
virtual void m() {cout << "B::m"; f();}
A* n() { cout << "B::n"; return this;}
}
class C : public A{
public:
virtual void f() {cout << "C::f";} //new method cause misses const
void g() const {cout << "C::g"; m();} //new method cause added const
void m() {cout << "C::m"; g(); f();}
}
***
A*q3 = new C();
(static_cast<B*>(q3->n()))->f(); //solution is A::n A::f
***
这是书上的错误还是正确的?对我来说,据我所知,我会将此标记为“未定义的行为”,但如果我错了,这是如何工作的?
static_cast can perform conversions between pointers to related
classes, not only from the derived class to its base, but also from a
base class to its derived. This ensures that at least the classes are
compatible if the proper object is converted, but no safety check is
performed during runtime to check if the object being converted is in
fact a full object of the destination type. Therefore, it is up to the
programmer to ensure that the conversion is safe. On the other side,
the overhead of the type-safety checks of dynamic_cast is avoided.
您可以轻松地转换为具有比原始字段更多字段的对象,尽管您指向的真实对象更短。然后,当您尝试访问这些字段时,就像缓冲区溢出一样 - 会产生非常令人惊讶的结果。这样做时要非常小心。
这会将 C*
对象转换为 A*
对象(通过 n()
),然后将 A*
对象转换为 B*
对象。最后它调用了一个 virtual 函数。
那么在实践中会发生什么?编译器将查看底层对象的虚拟 table 并找到要调用的函数 f
。虚拟 table 是内存中的实际 table。所以从 A 到 B 再到 C 的所有转换对 table 中的数据没有影响。
没有未定义的行为,确实 A::f
会被调用。
但是,这仅适用于虚函数。如果代码要使用 C 对象调用 B 的成员函数,并且如果该函数要使用 B 中可用但 C 中不可用的成员数据,那么一切都会变得一团糟。欢迎使用 C++,搬起石头砸自己的脚是一个理想的功能。
我正在做一些学习 C++ 中的继承和虚方法的练习。 所以我发现自己喜欢这个:
class A{
public:
virtual void f() const {cout << "A::f";}
virtual void g() {cout << "A::g"; m();}
virtual void h() {cout << "A::h"; f();}
void m() {cout << "A::m"; f();}
virtual A* n() { cout << "A::n"; return this;}
}
class B : public A{
public:
virtual void f() const {cout << "B::f";} //override
void g() {cout << "B::g"; A::n();} //override
virtual void m() {cout << "B::m"; f();}
A* n() { cout << "B::n"; return this;}
}
class C : public A{
public:
virtual void f() {cout << "C::f";} //new method cause misses const
void g() const {cout << "C::g"; m();} //new method cause added const
void m() {cout << "C::m"; g(); f();}
}
***
A*q3 = new C();
(static_cast<B*>(q3->n()))->f(); //solution is A::n A::f
***
这是书上的错误还是正确的?对我来说,据我所知,我会将此标记为“未定义的行为”,但如果我错了,这是如何工作的?
static_cast can perform conversions between pointers to related classes, not only from the derived class to its base, but also from a base class to its derived. This ensures that at least the classes are compatible if the proper object is converted, but no safety check is performed during runtime to check if the object being converted is in fact a full object of the destination type. Therefore, it is up to the programmer to ensure that the conversion is safe. On the other side, the overhead of the type-safety checks of dynamic_cast is avoided.
您可以轻松地转换为具有比原始字段更多字段的对象,尽管您指向的真实对象更短。然后,当您尝试访问这些字段时,就像缓冲区溢出一样 - 会产生非常令人惊讶的结果。这样做时要非常小心。
这会将 C*
对象转换为 A*
对象(通过 n()
),然后将 A*
对象转换为 B*
对象。最后它调用了一个 virtual 函数。
那么在实践中会发生什么?编译器将查看底层对象的虚拟 table 并找到要调用的函数 f
。虚拟 table 是内存中的实际 table。所以从 A 到 B 再到 C 的所有转换对 table 中的数据没有影响。
没有未定义的行为,确实 A::f
会被调用。
但是,这仅适用于虚函数。如果代码要使用 C 对象调用 B 的成员函数,并且如果该函数要使用 B 中可用但 C 中不可用的成员数据,那么一切都会变得一团糟。欢迎使用 C++,搬起石头砸自己的脚是一个理想的功能。