calling virtual from constructor

C

Christopher

I am beginnign to get the impression this is a very bad idea. Since I
have begun deriving classes my program is doing extremely odd things,
like mysteruiously exiting without ever throwing an exception, or
jumping to code that it shoudln't.

Can someone explain what happens when you call a virtual function or a
pure virtual function from a base class constructor?

How do you go about rearranging you code such that it does not do
this, when part of your intialization is going to require calling
methods of derived classes?
 
A

Alf P. Steinbach

* Christopher:
I am beginnign to get the impression this is a very bad idea. Since I
have begun deriving classes my program is doing extremely odd things,
like mysteruiously exiting without ever throwing an exception, or
jumping to code that it shoudln't.

Can someone explain what happens when you call a virtual function or a
pure virtual function from a base class constructor?

If you call an ordinary virtual function from a constructor of class T you get a
virtual call as usual (unless you qualify the call), but the type of the object
is T at this point, so you get the same effect as with any other T object.

If you call a pure virtual function you get UB.

Most compilers will however ensure that that call results in some run time
error, or if the call is sufficiently direct, detect at compile that you're
doing it.

How do you go about rearranging you code such that it does not do
this, when part of your intialization is going to require calling
methods of derived classes?

Oh, the problem of doing derived-class specific initialization.

It's just a matter of separating concerns in a proper way.

A few such ways are outlined in the FAQ (I once convinced Marshall to add it),
but the code below is the way I think is most generally useful:


<code>
#include <iostream>
#include <memory>
#include <string>

namespace api {
struct Widget
{
virtual ~Widget() {}
virtual std::string const typeName() const { return "Widget"; }
virtual std::string const text() const { return ""; }
};

struct Button: Widget
{
std::string myText;
Button( char const aText[] ): myText( aText ) {}
virtual std::string const typeName() const { return "Button"; }
virtual std::string const text() const { return myText; }
};
} // namespace api

namespace oo {

class Widget
{
private:
std::auto_ptr<api::Widget> myWidget;

Widget( Widget const& );
Widget& operator=( Widget const& );

protected:
api::Widget const& widget() const { return *myWidget; }

public:
class Init
{
public:
virtual ~Init() {}
virtual std::auto_ptr<api::Widget> newWidget() const
{
return std::auto_ptr<api::Widget>( new api::Widget );
}
};

Widget( Init const& initializer = Init() )
: myWidget( initializer.newWidget() )
{}

std::string const typeName() const { return myWidget->typeName(); }
};

class Button: public Widget
{
private:
Button( Button const& );
Button& operator=( Button const& );

public:
class Init: public Widget::Init
{
private:
std::string myText;
public:
Init( std::string const& aText ): myText( aText ) {}

virtual std::auto_ptr<api::Widget> newWidget() const
{
return std::auto_ptr<api::Widget>( new api::Button(
myText.c_str() ) );
}
};

Button( std::string const& text = "OK" ): Widget( Init( text ) ) {}
Button( Init const& initializer ): Widget( initializer ) {}

std::string text() const { return widget().text(); }
};
} // namespace oo

int main()
{
using namespace std;

oo::Button btn;

cout << btn.typeName() << " \"" << btn.text() << "\"" << endl;
}
</code>


Cheers, & hth.

- Alf
 
G

Greg Herlihy

* Christopher:



If you call an ordinary virtual function from a constructor of class T you get a
virtual call as usual (unless you qualify the call), but the type of the object
is T at this point, so you get the same effect as with any other T object..

There is a difference between a virtual function call made in T's
constructor (and destructor) and one made in any other T member
function. A virtual function call made in T's constructor (to the
object being constructed) will call either a member function of T or
one of its base classes. In particular, the call will not execute a
member function in a T-derived class that overrides the virtual
function - even if the class of the object being constructed does
derive from T and does override the virtual function being called.

So any C++ programmer who expects that a virtual function call made
from a constructor can be dispatched to a function in a derived class
- as is usually the case - is mistaken.

Greg
 
A

Alf P. Steinbach

* Greg Herlihy:
There is a difference between a virtual function call made in T's
constructor (and destructor) and one made in any other T member
function.
>
A virtual function call made in T's constructor (to the
object being constructed) will call either a member function of T or
one of its base classes. In particular, the call will not execute a
member function in a T-derived class that overrides the virtual
function - even if the class of the object being constructed does
derive from T and does override the virtual function being called.

Since you're writing this in response to what you quoted it's unclear what you mean.

One interpretation is that you mean the /same/ as what you quoted, in which case
it's correct.

Another interpretation is that you mean something /different/, e.g. that the
calls you're talking about are source code call specifications, or whatever, in
which case sorry, then it's /incorrect/.

So any C++ programmer who expects that a virtual function call made
from a constructor can be dispatched to a function in a derived class
- as is usually the case - is mistaken.

This, however, sounds like you mean the same as what you quoted?


Cheers & hth.,

- Alf
 
A

Alf P. Steinbach

* Daniel T.:
Very bad things.

Only in the case of calling a pure virtual routine, which is UB.

I've been coding in C++ professionally for 10 years now and have never
been in a situation where I thought this would even be helpful.

The case pops up now and then, in particular when wrapping an existing class
hierarchy (whether it's a conceptual hierarchy or one already coded in C++).

GUI programming is one example.

The FAQ outlines some useful techniques.


Cheers & hth.,

- Alf
 
C

Christopher

I've been coding in C++ professionally for 10 years now and have never
been in a situation where I thought this would even be helpful.

I've been coding professionally longer than that, and never run across
this particular situation I'm in.
I could code for 15 years and never even touch the entry point to an
application. It all depends on what you are working on and what you
are supposed to build on top of I guess. I'm sure things just have to
be redesigned. I wasn't happy with the design to begin with.
Know that the derived class constructor will be getting called
immediately after the base class constructor is done. Just do whatever
you want to the derived class' member-variables there.

That isn't the situation. It is currently set up such that, as soon as
the base class is constructed, a windows callback is called
indirectly, which in turn is calling virtual members to notify them of
events, when those derived classes haven't even been constructed yet.
I thought it was fishy.
 
J

James Kanze

Very bad things.

More or less. If the function isn't pure virtual, the behavior
is well defined. Whether it is what you want or not is a
different issue.
I've been coding in C++ professionally for 10 years now and
have never been in a situation where I thought this would even
be helpful.
Know that the derived class constructor will be getting called
immediately after the base class constructor is done. Just do
whatever you want to the derived class' member-variables
there.

I don't think that's the point. The most frequent case I've
seen where this occurs is when the template method pattern is
used. The answer is, as Alf said, to use the strategy pattern
instead. (One trick here is to derive from the base class,
making the concrete strategy---the delegate---a private base of
the derived class, e.g.:

class Base
{
protected:
Base( Strategy* strategy ) ;
} ;

class Derived : private DerivedStrategy, public Base
{
Derived() : Base( this ) {}
} ;

Note that because the DerivedStrategy is listed first, it will
be constructed before the Base.

(The actual code must be a bit more complicated than that; the
implicit conversion in the base initializer is undefined
behavior, and I've actually encountered one compiler where it
doesn't work. So I wrap the DerivedStrategy in a simple class
which has a member function to return the pointer to the
strategy.)
 
A

Alf P. Steinbach

* Juha Nieminen:
Is that so even if the pure virtual function had an implementation in
the base class?

If it is pure in class T and the call originates from a T constructor, yes.

This holds even if it has an implementation in class T, and the call is unqualified.

It can have an implementation and still be declared as pure (that is, "= 0").


Cheeers,

- Alf
 
J

James Kanze

Is that so even if the pure virtual function had an
implementation in the base class?

If the call is virtual, yes. Basically, if dynamic name
resolution resolves to a pure virtual function, the behavior is
undefined. You can use a qualified name to call it, however,
and that is well defined.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top