Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Providing initialized members to base class constructor

Let's say I have flawed C++ code like this:

struct A final {
    A(); // Initializes somethingShared

    shared_ptr<Something> somethingShared;
};

struct B {
    B(const A& a);
};

struct C : B {
    C()
    : B(a) {} // Uh-oh

    A a;
};

C should be-a B, so it inherits from it. But to initialize a B, we need an instance of A. C has to provide one, but how? In the above code, a is used uninitialized, because bases are initialized before members. I need to somehow initialize A before B.

If A wasn't final, I could inherit privately from A:

struct C : private A, public B {
    C()
    : B(*this) {}
};

But because it's final, I do this:

namespace detail {
    struct C_Base {
    protected:
        A a;
    };
}

struct C : private detail::C_Base, public B {
    C()
    : B(detail::C_Base::a) {}
};

Or I could use weird hacks like this:

struct C : B {
    C(const A a = A())
    : B(a),
      a(a) {}

    A a;
};

Is there a better way to do this?

like image 264
basteln Avatar asked Dec 05 '25 19:12

basteln


1 Answers

You could do it with a private constructor and a pointer:

class C : B {
private:
    const std::unique_ptr<A> m_aPtr;
    C(A* a) : B(*a) , m_aPtr(a), m_a(*a){}
public:
    C() : C(new A()) {}

    A& m_a;
};

This will ensure that

  • A is fully constructed before constructing B
  • A is only constructed once and not copied
  • m_aPtr will stay valid for the lifetime of the class (due to const) and will destroy A on class destruction properly (like an instanced member)
  • You can use m_a with the same syntax as an instanced member, because it's a reference. If it's ok for you, you could also leave m_a away and work only with the pointer m_aPtr.
like image 190
user2328447 Avatar answered Dec 07 '25 09:12

user2328447



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!