Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Calling virtual function from base class constructor

80 views
Skip to first unread message

Juha Nieminen

unread,
Sep 8, 2017, 2:43:40 PM9/8/17
to
I have quite a design dilemma, which I will introduce with a quiz
question: What does the following print?

//-------------------------------------------------------------
#include <iostream>

class Base
{
public:
Base { func(); }

virtual void func() const
{ std::cout << "base\n"; }
};

class Derived: public Base
{
public:
virtual void func() const override
{ std::cout << "derived\n"; }
};

int main() { Derived derived; }
//-------------------------------------------------------------

I understand why it does what it does. However, this poses a
problem.

I have a base class that implements certain functionality, and
is often instantiated directly. Many details of this functionality
can be specialized by derived classes, by implementing certain
virtual functions of the base class. These virtual functions specify
how the base class should behave in diverse situations. These
virtual functions may, for instance, return values which the base
class uses (such as colors, textures and other such stuff).

In some cases the base class needs to know these values in its
constructor, as well as elsewhere (during the existence of the
instance).

A very simplified (and simplistic) example of how it might work
(the actual situation is more complicated):

//-------------------------------------------------------------
class Base
{
public:
Base(some_parameters)
{
doStuffWithValues(getValues());
}

void anotherFunction(some_parameters)
{
doStuffWithValues(getValues());
}

private:
void doStuffWithValues(Values);

protected:
virtual Values getValues() const;
};
//-------------------------------------------------------------


You might immediately see the problem: It's getting the incorrect
values in its constructor, because it's getting its own values,
rather than the ones from the derived class.

I wonder if there's a nice and clean solution to this (which,
preferably, doesn't require changing the signature of the
base class constructor).

Bo Persson

unread,
Sep 8, 2017, 2:54:38 PM9/8/17
to
The nice and clean solution IS to pass the values needed as parameters
to the constructor.

The base class might then even store the values it is passed and you
don't have to make getValues virtual.



Bo Persson

Scott Lurndal

unread,
Sep 8, 2017, 2:55:08 PM9/8/17
to
One must ask _where_ does the derived class get the values
from? If from the derived constructor, then they could have been
passed to the base class constructor as well.

You might consider using an 'init' paradigm - where the base and
derived classes have init members instead of constructors, where
the derived init member explictly calls the base init member (and
the creator of either object calls the init function explicitly
after creating the object). As the object is fully realized by
the time the init member is called, the base class init function
can use the virtual functions without issue.

Alf P. Steinbach

unread,
Sep 8, 2017, 5:39:29 PM9/8/17
to
On 9/8/2017 8:43 PM, Juha Nieminen wrote:
> [snip]
There are many type safe solutions, and I once convinced Marshall to put
them in the FAQ,
<url:
https://isocpp.org/wiki/faq/strange-inheritance#calling-virtuals-from-ctor-idiom>

Also see this old blog posting of mine, which provides more holistic
concrete examples instead of just a listing of techniques,
<url:
https://alfps.wordpress.com/2010/05/12/how-to-avoid-post-construction-by-using-parts-factories/>

Bjarne discusses some aspects of why the 1990's two-phase construction
solution is bad, in <url: http://www.stroustrup.com/3rd_safe0.html>
(search the PDF for "init"), but he fails to address why it was so
commonly used, namely to solve your problem in a child's way, sort of.

Summing up:

• Don't use two-phase construction.
• Somehow (constructor args, templating) pass the requisite info to the
base class constructor.


Cheers & hth.,

- Alf

Juha Nieminen

unread,
Sep 11, 2017, 3:35:09 AM9/11/17
to
Bo Persson <b...@gmb.dk> wrote:
> The nice and clean solution IS to pass the values needed as parameters
> to the constructor.
>
> The base class might then even store the values it is passed and you
> don't have to make getValues virtual.

There are many such virtual functions, which derived classes can
optionally specialize in order to affect how the base class behaves.
It wouldn't make much sense to make them all mandatory, and have the
base class needlessly increase its own size by storing all of those
values within itself (especially since these are often values that
are not tied to a specific object, but are the same for all objects
of the same derived type.)

The values in question shouldn't be added to the public constructor,
because they are not a business of the outside code. It's an internal
implementation detail.

I suppose I could make an overloaded protected constructor just for
this purpose, but this is also somewhat dubious design, because I'm
now making the protected interface less abstract (from the perspective
of derived classes). Now the derived class would need to "know" that
the base class requires the value in its constructor. If in the
future the base class constructor is changed to require another
value, all the derived classes would need to be changed as well
(even if that value is one that's already handled by an existing
virtual function). It also feels like borderline code repetition
(because the derived class needs to be passing the same value to
the base class in two places).

Juha Nieminen

unread,
Sep 11, 2017, 3:41:27 AM9/11/17
to
Scott Lurndal <sc...@slp53.sl.home> wrote:
> One must ask _where_ does the derived class get the values
> from? If from the derived constructor, then they could have been
> passed to the base class constructor as well.

See my other reply for why this just doesn't feen like the best
possible design.

> You might consider using an 'init' paradigm - where the base and
> derived classes have init members instead of constructors, where
> the derived init member explictly calls the base init member (and
> the creator of either object calls the init function explicitly
> after creating the object). As the object is fully realized by
> the time the init member is called, the base class init function
> can use the virtual functions without issue.

The problem is that now the calling code would need to be burdened
by having to explicitly call an "init()" function for each object
that's created.

(It's not possible to have the derived class constructor call it
because, remember, the base class can be instantiated itself, and
thus it would need to call its own init() function. It would end
up being called twice, the first time with the wrong vtable if
this is actually a derived class object.)

Scott Lurndal

unread,
Sep 11, 2017, 8:50:37 AM9/11/17
to
"Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:

>Bjarne discusses some aspects of why the 1990's two-phase construction
>solution is bad, in <url: http://www.stroustrup.com/3rd_safe0.html>

Bad is your value judgement, not reflected by the reference, which
simply generalizes that the two-phase construction paradigm has
its own set of constraints that must be worked within while not
explicitly acknowleging that such implementations solve viable problems
efficiently.


>(search the PDF for "init"), but he fails to address why it was so
>commonly used, namely to solve your problem in a child's way, sort of.

It was used for years before RAII was even a gleam in someone's eye.

Calling a child's way is foolish and insulting.

Scott Lurndal

unread,
Sep 11, 2017, 8:51:42 AM9/11/17
to
Juha Nieminen <nos...@thanks.invalid> writes:
>Scott Lurndal <sc...@slp53.sl.home> wrote:

>
>> You might consider using an 'init' paradigm - where the base and
>> derived classes have init members instead of constructors, where
>> the derived init member explictly calls the base init member (and
>> the creator of either object calls the init function explicitly
>> after creating the object). As the object is fully realized by
>> the time the init member is called, the base class init function
>> can use the virtual functions without issue.
>
>The problem is that now the calling code would need to be burdened
>by having to explicitly call an "init()" function for each object
>that's created.

Yes, of course. How is that a problem?

Paavo Helde

unread,
Sep 11, 2017, 9:22:31 AM9/11/17
to
Seconded. There is nothing wrong in using 'init' if the alternatives are
worse.

If the class is instantiated in many places or you don't like two-line
creation code, make a small factory function and call this instead.

Cheers
Paavo




Alf P. Steinbach

unread,
Sep 11, 2017, 6:25:55 PM9/11/17
to
On 9/11/2017 2:50 PM, Scott Lurndal wrote:
> "Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>
>> Bjarne discusses some aspects of why the 1990's two-phase construction
>> solution is bad, in <url: http://www.stroustrup.com/3rd_safe0.html>
>
> Bad is your value judgement,

Yes.

> not reflected by the reference,

Wrong.


> which
> simply generalizes that the two-phase construction paradigm has
> its own set of constraints that must be worked within while not
> explicitly acknowleging that such implementations solve viable problems
> efficiently.

Wrong.


>> (search the PDF for "init"), but he fails to address why it was so
>> commonly used, namely to solve your problem in a child's way, sort of.
>
> It was used for years before RAII was even a gleam in someone's eye.

Yes.


> Calling a child's way is foolish

Wrong.


> and insulting.

Yes.

Juha Nieminen

unread,
Sep 13, 2017, 3:07:02 AM9/13/17
to
Scott Lurndal <sc...@slp53.sl.home> wrote:
>>The problem is that now the calling code would need to be burdened
>>by having to explicitly call an "init()" function for each object
>>that's created.
>
> Yes, of course. How is that a problem?

It transfers initialization duties to the calling code, which is very bad
object-oriented design. Not significantly better than transferring freeing
duties to the calling code (which is very much against good OO design and
the RAII principle).

It's very easy to forget to call the init() function in many situations
(in the same way as it would be easy to eg. call 'delete' to destroy the
object.)

asetof...@gmail.com

unread,
Sep 13, 2017, 3:14:20 AM9/13/17
to
I agree... All difficulties have to disappear in code (but can be traced in library). I not understand where to use "virtual" there is some problem that should resolve good with a class use virtual?
0 new messages