Could anyone help me understand this behaviour? To be short:
Here is what I have boilt it down to:
#include <iostream>
#include <vector>
// A base class
struct Base {
// A polymorphic method
virtual void describe() const {
std::cout << "Base" << std::endl;
};
virtual ~Base(){
std::cout << " Base destroyed" << std::endl;
};
};
// A specific interface
struct Interface {
virtual ~Interface(){
std::cout << " Interface Destroyed" << std::endl;
};
virtual void specific() = 0;
};
// A derived class..
struct Derived : public Base, public Interface {
virtual void describe() const {
std::cout << "Derived" << std::endl;
};
virtual void specific() {
std::cout << "Derived uses Interface" << std::endl;
};
virtual ~Derived() {
std::cout << " Derived destroyed" << std::endl;
};
};
int main() {
// Test polymorphism:
Base* b( new Base() );
Derived* d( new Derived() );
b->describe(); // "Base"
d->describe(); // "Derived"
// Ok.
// Test interface:
d->specific(); // "Derived uses Interface"
Interface* i(d);
i->specific(); // "Derived uses Interface"
// Ok.
// Here is the situation: I have a container filled with polymorphic `Base`s
std::vector<Base*> v {b, d};
// I know that this one implements the `Interface`
Interface* j((Interface*) v[1]);
j->specific(); // " Derived destroyed"
// " Interface destroyed"
// " Base destroyed"
// Why?! What did that object do to deserve this?
return EXIT_SUCCESS; // almost -_-
}
Can anyone tell me what I am missing there?
Interesting fact : If I swap the definitions of Base::~Base
and Base::describe
, then the object describes itself instead of being destroyed. How come the order matters in method declarations?
This is a good reason to avoid C-style casts. When you do:
Interface* j((Interface*) v[1]);
That is a reinterpret_cast
. A C-style cast will try to do, in order: const_cast
, static_cast
, static_cast
then const_cast
, reinterpret_cast
, reinterpret_cast
then const_cast
. All of these casts, in this case, are wrong! reinterpret_cast
in particular will just be undefined behavior and it honestly doesn't even matter why you see the specific behavior you see † . Undefined behavior is undefined.
What you want to do instead is:
Interface* j = dynamic_cast<Interface*>(v[1]);
That is the correct cast through the runtime dynamic hierarchy, and will give you the correct Interface*
corresponding to v[1]
(or nullptr
, if v[1]
did not have this runtime type). Once we fix that, then j->specific()
prints Derived uses Interface
, as you would expect.
Base
does not have a specific
, it's possible that the offset of that particular function lines up with ~Base()
, so the effect is that you're directly calling the destructor - which is why you see what you see.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.