-3

I am trying to call an overriden function from the parent, and found out that it just crashes.

This is quite hard to describe, so here the minimal reproducible code:

#include <iostream>

class A
{
public:
    A()
    {
        init1();
    }
    
    void init1()
    {
        printf("1");
        init2();
        printf("2");
    }

    virtual void init2() = 0;
};

class B : public A
{
public:
    B()
    : A()
    {}

    void init2() override
    {
        printf("hello");
    }
};

int main()
{
    B b;
    return 0;
}

On MSVC 2019 it crashes, on http://cpp.sh/ it outputs "1" and then main() returns 0, but we never see "hello" or "2".

  1. Why does it crash? What happens from a low level point of view? Is A trying to call its own init2()?

  2. Is there a way of doing it, so I don't have to, in every derived class, add init2() in its constructor?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Nox
  • 713
  • 7
  • 16
  • 1
    The problem comes when you call `init1();` during `A`'s constructor. Calling virtual functions during constructors and destructors is dangerous because the most-fully-derived class isn't actually in a valid state--`A`'s constructor has to finish entirely before `B`'s executes, but you have to have a `B` for `init2();` to mean anything. – Nathan Pierson Mar 23 '21 at 00:09
  • You can't call `init2` until you have an instance of class `B` because only class `B` has an implementation of `init2`. Thus calling `init2` from the constructor of class `A` is a no go. – David Schwartz Mar 23 '21 at 00:14
  • I've read every links sent. Funny that I could not find any with my own words. I found it hard to describe and got really poor results. Well, so I guess my question 1 is answered, do you have some about the 2) please ? – Nox Mar 23 '21 at 00:18
  • 2
    @Nox Have a "factory" that produces instances of class `B` by constructing them and then calling `init2` on them. Do not allow "outsiders" to access these functions (by making them `protected` or `private`). – David Schwartz Mar 23 '21 at 00:20
  • To answer your 2), you'll need to implement another `init` function and call that sometime after the object is constructed. – Thomas Matthews Mar 23 '21 at 00:31

1 Answers1

7

You can't call a derived class's overriden methods from within a base class constructor (or destructor). The derived class portion of the object doesn't exist yet.

So, to answer your questions:

  1. yes A::A() is trying to call A::init2(), not B::init2(), and thus crashes from calling a pure virtual method.

  2. There are ways (like via CRTP) for a base class constructor to call a derived class method, but doing so has limitations to it (ie, not being able to access any derived class data members since they still don't exist yet, only base class data members can be accessed). In your example, B::init2() doesn't access anyB data members, so it is possible for A::A() to call B::init2(), but in general you really need to wait for B to begin/finish constructing itself before you can safely call B::init2().

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770