Topic: constructing an object with virtual function call to derived classes
Author: davie@c-plusplus.de (davie)
Date: Tue, 10 Aug 2004 06:12:17 GMT Raw View
only an immature idea:
(following problem:
struct Base {
Base () { bar (); }
virtual void bar () { ... }
}
struct Derived : Base {
void bar () {...}
}
Derived d;
of course, Base::bar will be called. but what, if the programmer
wants any (Derived)::bar to be called instead of it?
)
the ideas on http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.4
are good, but not perfect.
i got another idea and wanted to ask you for your opinion.
class LateCall;
class LateCallHolder { //only a dumb smart pointer
LateCall *fun;
public:
LateCallHolder () : fun(0) {}
~LateCallHolder ();
LateCallHolder (LateCall *f) : fun(f) {}
LateCall &reset (LateCall *f); //with this special ability
};
Of course, you have to pay sth:
class Base {
Base () {}
friend class LateCall;
public:
Base (LateCall& late_this);
virtual ~Base () {}
virtual void bar () { cout << "Base::bar()\n"; }
};
define two classes instead of one:
class LateCall : public Base {
Base *obj;
map<string,bool> callreqs;
public:
LateCall (Base *b) : obj(b) {}
void bar () { callreqs["bar"] = true; }
~LateCall () {
if (callreqs["bar"]) obj->bar();
}
};
LateCall &
LateCallHolder::reset (LateCall *f) {
delete fun;
fun = f; return *f;
}
LateCallHolder::~LateCallHolder () {
delete fun;
}
LateCall has to implement all virtual and pure virtual functions.
but instead of implementing a specific behavior, it (1) delegates the
calls to
another Base object. and (2): it calls the functions when being
destroyed.
a few things have to be done: the order in which the functions are
called
maybe with sth like boost::function. remember: this is only an odd
example of what I mean.
Next: implement an example:
Base::Base (LateCall &late_this) {
late_this.bar(); //calls bar for this, but in an obscure
way it will call Derived::bar (introduced later)
cout << "Base::Base()\n"; //will execute immediately
}
class Derived : public Base {
public:
Derived (LateCallHolder = LateCallHolder()); //important!
//this has to be a default argument in order to get the right
lifetime for the object.
void bar () { cout << "Derived::bar()\n"; }
};
Derived::Derived (LateCallHolder later)
: Base(later.reset(new LateCall(this))) //now, this is tricky: bind
"this" to the LateCall object
{
cout << "Derived::Derived()\n";
//at this point, all functions called in Base will be executed,
due to the LateCall object being destroyed (remember: it executes the
functions on destruction, an therefore it calls Derived->base)
}
int main () {
Derived d;
}
thus, the output is:
Base::Base()
Derived::Derived()
Derived::bar()
as expected.
i hope that i didn't miss some rules but i think it will compile
(can't try it at the moment) and run without undefined behavior. stick
the pieces together and try.
i try to emulate a simple two phase construction but avoiding that
awful init() function.
i think the main problem is the order of the function calls.
what do you think about it?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]