nojhan
nojhan

Reputation: 1332

C++ default initialization in constructor of an inherited reference member

I have a base class that updates an extern reference, and I want to build an inherited class that would embed this reference as a member. A kind of default initialization of the reference.

I came up with the following solution:

#include<iostream>

class Statefull
{
public:
    Statefull( int& ref ) : _base_ref(ref) {}
    int& _base_ref;
    // update the extern variable
    void work() { std::cout << ++_base_ref << std::endl; }
};

class Stateless : public Statefull
{
public:
    // use a temporary allocation
    Stateless( int* p = new int() ) :
        // we cannot initialize local members before base class:
        // _dummy(), Statefull(_dummy)
        // thus, initialize the base class on a ref to the temporary variable
        Statefull(*p),
        _tmp(p),
        _dummy()
    {
        // redirect the ref toward the local member
        this->_base_ref = _dummy;
    }
    int* _tmp;
    int _dummy;
    // do not forget to delete the temporary
    ~Stateless() { delete _tmp; }
};

int main()
{
    int i = 0;
    Statefull full(i);
    full.work();

    Stateless less;
    less.work();
}

But the need of a temporary allocation in a default argument of the constructor seems quite ugly. Is there a more elegant way to achieve this kind of default initialization while keeping a reference in the base class constructor?

Upvotes: 3

Views: 1017

Answers (3)

Tadeusz Kopec for Ukraine
Tadeusz Kopec for Ukraine

Reputation: 12413

Everything can be solved using some more classes

class StateForStateful
{
protected:
    int state;
};

class Stateless: private StateForStateful, public Stateful // order is important
{
public:
     Stateless():Stateful(this->state) {}
};

Upvotes: 0

R. Martinho Fernandes
R. Martinho Fernandes

Reputation: 234654

Well, the Stateless class is violating the rule of three. But I'll assume that's because this is just sample code to exhibit the real problem.

Now, to actually address the problem: it's perfectly valid to bind a reference to an uninitialized variable, as long as its value is not used before initialization actually happens.

Stateless() : Statefull(_dummy), _dummy() {}

The present solution works, but it seems there's some misunderstanding about why it works.

    // redirect the ref toward the local member
    this->_base_ref = _dummy;

You cannot "redirect" references. You can only bind a reference once: upon initialization. Assigning to a reference assigns to the object it refers to. In this case, this->_base_ref = _dummy is exactly the same as *_tmp = _dummy : it assigns the value of _dummy to *_tmp. _base_ref, however, still refers to *_tmp (you can test this with assert(&_base_ref == tmp)).

Upvotes: 4

fork0
fork0

Reputation: 3459

I think this might work:

StateLess(): Statefull(*new int) {}
~StateLess() { delete &_base_ref; }

You can't do without temporaries, but they don't have to be in the classes definitions.

Upvotes: 1

Related Questions