0

Beginner here, my simplified code:

A.h

class A{
public:
  A(int x);
private:
  int _x;
}

A.cpp

A::A(int x) 
  : _x(x)
{
}

B.h

class B : public A{
public:
  B()
private:
  int _y = 1;
}

B.cpp

B::B()
  : A(1) //works
  : A(_y) //doesn't work
{
}

Why does the initialization with a member of B not work, but with a bare integer it does. I mean I can just go for the working method but I'd like to know the cause.

Thanks for any helpers!:)

  • 2
    When the object of the base class is created then the members of the derived class is not yet created. – Vlad from Moscow Jun 03 '22 at 23:39
  • [Why should I always enable compiler warnings?](https://stackoverflow.com/questions/57842756/why-should-i-always-enable-compiler-warnings) – JaMiT Jun 04 '22 at 00:34
  • More general reference: [Construction and initialization order guarantees](https://stackoverflow.com/questions/2517050/) – JaMiT Jun 04 '22 at 00:36

2 Answers2

1

Vlad has given you the reason, here's a workaround that avoids the need to duplicate your magic number:

class B : public A{
public:
  B();
private:
  static const int initial_y = 1;
  int _y = initial_y;
};

B::B()
  : A(initial_y)
{
}

Demo

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48
  • Thanks! Why would I `int _y = initial_y`? Couldn't I just skip this step? – CappedMonke Jun 04 '22 at 00:34
  • 1
    It depends on how you are using `_y`. This code preserves the behavior of your original code by giving `_y` an initial value (if you omit `_y = initial_y` then `_y` will be *uninitialized*), while still giving you the ability to re-assign `_y` later, if you wanted to. But this way allows you to both initialize `A()` and `_y` with the same value, without having to define that value twice. – Remy Lebeau Jun 04 '22 at 00:42
0

A derived class's base classes are fully initialized before any of the derived class's data members are initialized.

In the case of:

class B : public A{
public:
  B();
private:
  int _y = 1;
}

B::B()
  : A(_y)
{
}

Data members that have initial values in their declarations are implicitly handled by the constructor's member initialization list. So, in this case, the compiler treats the above code as-if you had written it like this instead:

class B : public A{
public:
  B();
private:
  int _y;
}

B::B()
  : A(_y), _y(1)
{
}

As you can see, A(_y) is called before _y is initialized, which is undefined behavior.

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