Re: pure virtual functions and runtime id
On Feb 19, 10:08 am, Juha Nieminen <nos...@thanks.invalid> wrote:
cerenoc wrote:
But isn't this the whole point of polymorphism?
The problem you presented has nothing to do with polymorphism, but
with object scope.
As I pointed out in my response to Martin York, it's not a
question of scope per se, but object lifetime. In the case of
auto variables (non-static variables with local scope), lifetime
does correspond to scope, but this is not a general principle.
Your derived objects are destroyed before the last
var->whoami() call. By all intents and purposes 'var' is not
pointing to an object of the derived class type anymore,
because it has been destroyed (because it went out of scope).
That's why you are getting the error.
For all intents and purposes, 'var' doesn't point to anything,
and just accessing var is undefined behavior. Anything can
happen.
As it happens, the object still physically exists because it's a
static instance,
First, the object(s) in question weren't static instances, but
local variables. And the objects don't "still exist". The
memory in which they were placed still exists (not guaranteed,
but true for most implementations), however, and it may contain
remenents of the object.
but most C++ compilers work in a way that when an object of
the derived type is destroyed, any virtual functions accessed
through a base class type pointer/reference will be purely of
the base class type, even if they point to this destroyed
static object of the derived type. This means that your
pointer is not seeing a derived class object anymore, only a
base class object. That's why you are getting an error message
instead of a crash.
What he's seeing is a pointer to nothingness. What's
doubtlessly actually happening is that without the std::string
member, the destructors are sort of trivial, doing nothing but
changing the vptr (the way virtual functions are usually
implemented); the compiler recognizes this, and doesn't bother
with them. And since nothing else has accessed the memory which
once contained the object, the code appears to work. With
std::string, the compiler must generate a destructor (to call
the non-trivial destructor of std::string), and this destructor
also updates the vptr to reflect the type in the destructor
(although in fact, the modified vptr will never be used).
Whatever happens, however, is really undefined. Even the
slightest changes in the source may result in the memory where
the object was being used, with desasterous consequences.
That's why the behavior is undefined.
[...]
The reason for this is that when the code reaches the 'cleanup()' call
in the base class destructor, the derived class part has already been
destroyed and by all intents and purposes doesn't exist anymore. From
the point of view of the base class destructor the object is purely of
type 'Base', nothing else. Because of this, the dynamic binding logic
calls the base class 'cleanup()' because that's what this object is at
this point. There simply is no way to call a derived class function from
a base class destructor.
Yes, it's a bummer, but it has a relatively simple solution:
It's a bummer that you can't call a function on something which
doesn't exist---whose class invariants no longer hold?
class Derived: public Base
{
public:
~Derived() { cleanup(); }
virtual void cleanup() { std::cout << "Derived cleanup\n"; }
};
A bit less automatic, but that's just a side-effect of OOP.
Or just have the derived classes put the cleanup code in the
destructor, where it belongs. (There are cases where a
"post-construtor" would be nice, i.e. code in the base class
that automatically runs immediately after the constructor of the
most derived class has finished, but I've never encountered
anything similar for a destructor, where I've wanted a
pre-destructor. Also, there are tricks which allow simulating a
post-constructor in most of the usual cases---although if you
use them, you should document very well what is going on,
because otherwise, you're going to have some maintenance
programmer really scratching his head.)
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34