5

I'd like to follow the RAII(resource acquisition is initialization) idiom throughout my code but I'm also doing the template pattern where I'm developing generic versions of my classes and using them to build a common codebase for certain things. Sometimes I need to enforce an initialization sequence where I would need to call the specialized object's virtual functions in the constructor but that's not possible in C++. The only solution I can think of is a two step initialization by calling an init function after the object is created but that breaks the RAII idiom. Is there any solution to this?

#include <memory>

class A {
public:
    A() {
        // I want to call B's foo() here
    }
    virtual void foo() = 0;
};

class B : public A {
public:
    B() {};
    virtual void foo() {};
};

void main() {
    std::unique_ptr<A> a(static_cast<A*>(new B));

    // Use b polymorphically from here...
}
  • Do you have to use inheritance-based polymorphism or would type erasure or even static polymorphism also be an option? – 5gon12eder Jan 7 '17 at 8:05
  • Related: stackoverflow.com/questions/962132/… – Blrfl Jan 7 '17 at 12:06
  • Is it possible to use lazy evaluation? Perhaps you can have an, e.g., fooCalled flag, so that the class internals can call foo immediately before its result is first needed rather than during initialisation. – Justin Time 2 Reinstate Monica Aug 11 at 16:21
6

The basic problem is here:

A() {
    // I want to call B's foo() here
}

Why do you want to call B's foo() here? How can something specific to B be relevant to the initialization of A, which has no idea at all about B? The answer will just about always point to a poor design.

One class of answers (quite commonly encountered, but apparently not relevant here) is when a virtual method is used to return a B-specific value that A will store and/or use. The poor design concept here is that a virtual method should be used to pass this value. A superior alternative is to pass the value from the derived class as an argument to the base class constructor. That way the base class doesn't have to worry at all how the value comes about.

Here, however, foo() has a void return signature. Whatever it does, it must do it in the context of B. Then, how can it affect anything about A? It could have access to a protected member, or it could call other base class methods. But why should any of these actions have to occur during A's initialization? Why not during B's initialization?

The basic point is that the initialization of A should be designed to depend on its constructor parameters only. That way, any derived class can achieve its specific customization of the base class by invoking the base class constructor from its own constructor with the appropriate values.

ADDENDUM: For the template method pattern, the best you can do is to enforce the implied discipline, with an organization on these lines:

class Base
{
public:
    virtual ~Base(); // for polymorphic destruction
protected: // to ensure invocation from derived classes only
    Base()
    {
        // pre-customization base class actions
    } 
    void finish_base() // virtual methods can be called from here!
    {
        // post-customization base class actions
    }
};

class Derived : public Base
{
public:
    Derived() : Base()
    {
        // derived class customized actions
        finish_base();
    }
};

This is not "two-phase" inasmuch as the Derived class initialization occurs entirely within its constructor. How that work is split up is internal to the implementation, and thus "unitary" from any outside perspective.

5

You could take the approach of making the constructor of A protected, the constructor of B private, and then make a class static helper to instantiate B; the static helper would then do the two stage initialization; this would ensure that the instantiation is always done correctly, and making the constructor private/protected ensures that you don't accidentally try to instantiate the class directly. This does have the downside that you can't instantiate the class on the stack or as a member -- it has to be on the heap.

  • why it can't be on stack? – Sarge Borsch Jan 7 '17 at 6:49
  • maybe there is a way to do it on the stack, but not like I described, because the static helper needs to return a pointer (remember, the constructor is private, so you can't just instantiate the class). Maybe you could do it with a templated wrapper and a protected constructor... – B.J. Jan 7 '17 at 6:58
  • A simple template for the static factory function should do the trick. – 5gon12eder Jan 7 '17 at 8:07
  • 2
    class A { A() {}; public: static A instance () { return A (); } }; No heap involved. – D Drmmr Jan 19 at 20:08
3

You can't call B's functions from A's constructor, because the B subobject doesn't exist yet.
Any design that'd rely on a virtual function call from a parent constructor is nonsensical.

The solution is simply to call foo() from B's constructor.

  • Many years ago Borland Pascal allowed this. It was a disaster because member variables had not been initialised when the virtual method was called. +1 for your answer. – kiwiron Jan 18 at 3:55

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.