4

I'm trying to make one class which requires member variables to be initialized first. I know why this happens, but is there a way around this?

Current print order: second first

Wanted print order: first second

#include <iostream>

struct A {
    A() {
        std::cout << "first" << '\n';
    }
};

struct B {
    B() {
        std::cout << "second" << '\n';
    }
};

struct C : public B {

    C() : a(), B() {

    }

    A a;

};

int main() {

    C c;

    return 0;
} 
pesuww
  • 105
  • 11

3 Answers3

6

Stick your members that need initializing first in a struct and inherit privately from that, before B.

struct A {
    A() { std::cout << "first" << '\n'; }
};

struct B {
    B() { std::cout << "second" << '\n'; }
};

struct Members { A a; };

struct C : private Members, public B {
    C() : Members(), B() {}
};

int main() {
    C c;
} 

The downside with this is that there is no way to avoid exposing the "member struct" to the outside world, but that shouldn't be a problem in practice.

molbdnilo
  • 64,751
  • 3
  • 43
  • 82
4

In C++ base classes will be initialized before any member variables of a derived class.

The best recourse given the information you've provided is to prefer composition over inheritance:

struct A {
    A() {
        std::cout << "first" << '\n';
    }
};

struct B {
    B() {
        std::cout << "second" << '\n';
    }
};

struct C {
    A a;
    B b;
};

This will exhibit the desired behavior

AndyG
  • 39,700
  • 8
  • 109
  • 143
-2

Make A a needed reference for C:

#include <iostream>

struct A {
    A() {
        std::cout << "first" << '\n';
    }
};

struct B {
    B() {
        std::cout << "second" << '\n';
    }
};

struct C : public B {
    C(const A& a) : _A(a), B() {}
    const A& _A;
};

int main() {
    A a;
    C c(a);
    return 0;
}
RoQuOTriX
  • 2,871
  • 14
  • 25
  • 1
    Why not `C(A a = {}) : B{}, _A{std::move(a)} {}`? It's usually better to pass by value when storing a copy. – Toby Speight Jun 15 '21 at 13:50
  • @RoQuOTriX That does not answer the question because explicit creating an object of the type A A a; has nothing common with the described problem. – Vlad from Moscow Jun 15 '21 at 13:53
  • @TobySpeight can you explain me the difference going on here? As I see, you pass a copy which then is moved? – RoQuOTriX Jun 15 '21 at 13:53
  • There's only moves (not a copy) if an rvalue is passed. That's the difference. – Toby Speight Jun 15 '21 at 13:54
  • @VladfromMoscow problem: "...requires member variables to be initialized first" solution: "initialized the member first". I see no problem here. If you want you can write a factory which does that for you... – RoQuOTriX Jun 15 '21 at 13:54
  • @TobySpeight but I don't want to copy it? – RoQuOTriX Jun 15 '21 at 13:55
  • 3
    Names that begin with an underscore followed by a capital letter (`_A`) and names that contain two consecutive underscores are reserved for use by the implementation. Don't define them in your code. – Pete Becker Jun 15 '21 at 13:55
  • @RoQuOTriX You are mistaken. It is not the member variable that is initialized first. It is the base class that is initialized first. The displayed message is related to the declaration A a;. – Vlad from Moscow Jun 15 '21 at 13:55
  • Exactly. That's why you want `std::move()`. – Toby Speight Jun 15 '21 at 13:55
  • 1
    @TobySpeight there is no copy being made, the member is a reference – 463035818_is_not_an_ai Jun 15 '21 at 13:56
  • @PeteBecker I did it for simplification but yes you are right! – RoQuOTriX Jun 15 '21 at 13:56
  • Oh yes, it's a reference. Oops. It was a value member in the original (so no lifetime issues to worry about). – Toby Speight Jun 15 '21 at 13:56
  • @VladfromMoscow the class itself needs that the "member" is initialized before hand. That is requirement fullfilled by design – RoQuOTriX Jun 15 '21 at 13:57
  • 1
    Technically the member (`_A`) is still initialized after `B`, though an `A` is constructed before `B`. Whether or not this applies to this question depends on why they want this order of initialization. – François Andrieux Jun 15 '21 at 13:57
  • @RoQuOTriX Do you understand what I have written? It is the sub-object of the base class that is initialized first in your program. The message relative to the class A that you see is issued by the declaration A a;. – Vlad from Moscow Jun 15 '21 at 13:59
  • @FrançoisAndrieux yes the real problem here is, that the question is not clear enough to give a good solution. – RoQuOTriX Jun 15 '21 at 13:59
  • @VladfromMoscow yes I understand that. It depends on the use-case WHY the user wants it in that order, then we can provide maybe a different or better solution. My solution requires A to be initialized before B and C which totally fullfills the given requirements – RoQuOTriX Jun 15 '21 at 14:00
  • There's a different between an object being _constructed_ and a member being _initialised_. This answer might be what's wanted, but you should be clear about why you've presented something different than requested. I wouldn't say that this "totally fullfills the given requirements" - it meets something similar to the requirements, and you should state what's different. It will matter if `B` is constructed with arguments that cause `this->A` to be accessed, for example. – Toby Speight Jun 15 '21 at 14:01
  • @RoQuOTriX We are specking about initialization of DATA MEMBER a before initialization of the base class. You answer has nothing common with such a situation. – Vlad from Moscow Jun 15 '21 at 14:02
  • @TobySpeight yes you are right, but I think we should OP not overhelm with bad coding style solutions like private inheritance and using a better solution like dependency injection – RoQuOTriX Jun 15 '21 at 14:03
  • @VladfromMoscow downvote it if that makes you happy. Maybe teach people writing cleaner code and better solutions instead of sticking to pitfalls like multi-inheritance and private inheritance – RoQuOTriX Jun 15 '21 at 14:04
  • @RoQuOTriX `private` inheritance is not inherently bad or unclean code. There are actually fewer risks involved in `private` inheritance than there are with `public` inheritance and it is a fully encapsulated design decision (it has no effect at all on the type's user). Where as the solution presented in this answer introduces a lifetime concern where the user has to be sure the `B` doesn't outlive the `A`. Furthermore, reference type data members introduce [very significant restrictions](https://stackoverflow.com/a/892303/7359094) and should be avoided. – François Andrieux Jun 15 '21 at 14:38