0

I am still quite new on here so I hope I am posting in right forum.

I am currently writing a small library where I realized I could use some kind of design pattern which lets one pass constructor arguments to initialization or allocation functions, and these can be further specialized in inherited classes.

Something like this:

class MyArgs{
  // basically just a wrapper/container
  // just a constructor and variables
  // everything public or friend of MyClassBase
};

class MyClassBase{
  MyClassBase(MyArgs a){
    doAllocation(a);
    doInitialization(a);
  }
  //... defining default doAllocation() and doInitialization() ...
};

class MyClassDerived : public MyClassBase{
  MyClassDerived(MyArgs a) : MyClassBase(a){}
  //... override doAllocation() and doInitialization() ...
};

Does there exist some kind of design pattern which makes this easier?

  • 2
    Note that in C++ (unlike in some other languages), virtual functions behave completely differently when called from a constructor compared to when called after construction has completed. – Bart van Ingen Schenau Jan 8 at 12:34
  • @BartvanIngenSchenau Aha! That does indeed sound quite important! It does seem to work on my experiment with g++. But maybe I don't know where to look. – mathreadler Jan 8 at 13:47
2

This will not work in view of C++ object lifecycle and the construction logic. Here is what happens:

  • you construct a MyClassDerived
  • Before the (empty) MyClassDerived constructor body is invoked, first the base object is constructed and then the member variables (with their default constructor unless you use a mem-initializer).
  • The MyClass constructor is therefore invoked at a time there is no complete MyClassDerived yet. So it doesn’t call the overridden functions, but the original ones of the base MyClass class.
  • The additional MyClassDerived members are then constructed. At this point only will the MyClassDerived object starts to exist and the overridden function be active. Unfortunately they are no longer called at this stage in your code.
  • Then the body of the MyClassDerived constructor is executed.

If you want your approach to work, you need to implement a two phase initialisation:

  • first the constructor creates the object, ensuring the minimum initializations
  • once the object is constructed, the first thing that is to be done is to invoke an initialising function. This would then properly invoke the overridden function, even if it is called from a function defined for the base class.

This pattern is cumbersome and error prone, since it is easy to forget the initialisation call in the constructing context (not to speak about unexpected copy construction or default construction).

If you nevertheless intend to use this pattern, then you should:

  • either make the constructor private and limit the access to the constructor using the builder pattern. This pattern is specially meant for a multistep construction process. Alternatively you could think of a factory method that would also be in good position to ensure proper two phase initialisation.
  • or consider implementing a state machine like design, in which the initialisation step would update the object’s state to a usable one. Maybe you could even let the object check the state at each function call and automatically perform second phase of initialisation if it wasn’t done before. But this, although it is convenient for the using context, would be an overhead on every call.
| improve this answer | |
  • Thank you for the answer. Yep, I realized the first part when I experimented, so I made a new constructor for the derived which calls it's own doAllocation(). It works, but is much uglier. – mathreadler Jan 8 at 15:37
0

There is the Factory Method pattern. Other Creational Patterns may help as well.

| improve this answer | |
  • 2
    You need to provide a more substantial answer than just a pair of links. Consider adding some narrative about each pattern, and why you think those patterns address the original question. – BobDalgleish Jan 8 at 14:42
0

I'm not an expert in C++ and I do not know what aspect you want to simplify. But I guess you could use some factory classes in order to pull out the initialization logic from your classes:

enter image description here

| improve this answer | |
  • You don't need factory classes in C++, there are free (template) functions – Caleth Jan 8 at 15:33
  • This is great! Actually quite close to how I ended up making a minimal example. – mathreadler Jan 8 at 20:49
0

Thank you very much for feedback, everyone.

Based on answers I came up with a minimal example that works for me.

I suppose we can call it a kind of combination of multi-stage construction and Factory.

template<class C, class Cargs>
class ArgFactory{ // Here is factory. The class C shall have C(Cargs a)
                  //                  and define a doAllocate(Cargs a)
public:
    static C* Create(Cargs a){
        C* lRet = new C(a);
        lRet->doAllocate(a); // This is now run after actual construction.
        return lRet;
    }    
    virtual void doAllocate(Cargs a) = 0; // This overrideable.
};

class IntegerArgs{
public:
    IntegerArgs(int a) : m(a){}
    int m;
};

class Integer : public ArgFactory<Integer,IntegerArgs>{
public:
    Integer(IntegerArgs a){}
    virtual void doAllocate(IntegerArgs a){
        m=a.m;
    }
    int m;
};
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.