views:

114

answers:

5

I'm looking for a clean C++ idiom for the following situation:

class SomeLibraryClass {
  public:
    SomeLibraryClass() { /* start initialization */ }
    void addFoo() { /* we are a collection of foos */ }
    void funcToCallAfterAllAddFoos() { /* Making sure this is called is the issue */ }
};
class SomeUserClass : public SomeLibraryClass {
  public:
    SomeUserClass() {
      addFoo();
      addFoo();
      addFoo(); // SomeUserClass has three foos.
    }
};
class SomeUserDerrivedClass : public SomeUserClass {
  public:
    SomeUserDerrivedClass() {
      addFoo(); // This one has four foos.
    }
};

So, what I really want is for SomeLibraryClass to enforce the calling of funcToCallAfterAllAddFoos at the end of the construction process. The user can't put it at the end of SomeUserClass::SomeUserClass(), that would mess up SomeUserDerrivedClass. If he puts it at the end of SomeUserDerrivedClass, then it never gets called for SomeUserClass.

To further clarify what I need, imagine that /* start initialization */ acquires a lock, and funcToCallAfterAllAddFoos() releases a lock.

The compiler knows when all the initializations for an object are done, but can I get at that information by some nice trick?

A: 

Try the Non-virtual Interface Idiom. Make your public method non-virtual, but have it call a private virtual method. The derived classes override this private virtual method (yes, derived classes can override private virtuals). Put the lock stuff in the public non-virtual method around the call to the private virtual method.

EDIT: After looking at the code more carefully, I think you might be better off having a constructor in the base class that accepts a container of Foo objects and adds them.

Fred Larson
How is that going to fix the problem? Someone still has to call the virtual method when construction is complete.
mos
No, the only caller of the virtual method is the non-virtual method. The derived classes don't need to call anything.
Fred Larson
But then the virtual method would (indirectly) be called by the base class constructor, which is the *first* to run, not the *last*...
Thomas
Ugh, I didn't look carefully enough at the code to see this was called from a constructor.
Fred Larson
A good answer for a different question :)
Mike Elkins
@Mike Elkins: Yeah, I hate it when I do that. But maybe my edit is closer to the mark?
Fred Larson
A: 

As C++ does not allow reflection, no, you cannot directly obtain this information. (Though there may be some way I'm unaware of to prevent compilation from succeeding)

However, I question the design here. Wouldn't it make more sense to release the lock once SomeLibraryClass is done? If you're concerned about the efficiency of calling AddFoo multiple times your library can provide a member accepting a std::vector<Foo> which would only have to acquire and release the lock once.

Billy ONeal
To clarify, the lock needs to be held for the duration of the adding, and not released until the object is ready for use. Releasing the lock after each addFoo wouldn't just be inefficient, but incorrect.
Mike Elkins
@Mike Elkins: I'm not saying release it after each AddFoo. I'm saying that a simple solution is to pass a `vector<Foo>` which allows a single function call to add all Foos. Then the function that adds foos can release the lock on it's own.
Billy ONeal
As for the method taking a vector, that might work, but how would you make it easy to create SomeUserDerrivedSubclass? I have to hold the lock through the call from SomeUserClass until the end of SomeUserDerrivedSubclass.
Mike Elkins
@Mike Elkins: No. But if that's the case enforcing the derived constructors to call your method does not work either, because `SomeUserClass` finishes constructing and calls your method before `SomeUserDerivedClass` finishes constructing. `SomeUserClass` has no magical way of knowing it's constructing a derived class.
Billy ONeal
+9  A: 

I would probably implement this with a factory of some sort. The following code should be read as pseudocode, I haven't tried compiling it or anything.

class LibraryClass
{
public:
   template<typename D>
   static D *GetNewInstance()
   {
      // by assigning the new D to a LibraryClass pointer, you guarantee it derives from LibraryClass at compile time
      // that way, the user can't accidentally type "LibraryClass::GetNewInstance<int>()" and have it work
      LibraryClass *c = new D();
      c->funcToCallAfterAllAddFoos();
      return c;
   }

   ...
};
mos
+1. This is the only answer here which allows the "SomeUserDerrivedClass" pattern to actually work (where the derived class inherits the `Foo`s of the parent)
Billy ONeal
No, any constructor passing approach would work, you just build up on the collection passed from derived classes.
Stephen
However, all derived class constructors would have to be `public`, so it would be possible to accidentally bypass the factory. Any way around that?
Thomas
@Thomas: I fail to see that making the constructors public is a requirement. The factory can (and probably should) be a friend class/function. Note that this does not break encapsulation nor adds coupling: the factory and the created objects are tightly coupled already, and you keep control of the factory method so you have as much control as you would have when implementing a method of the class.
David Rodríguez - dribeas
The implementation is lacking an `static_cast` back to `D` in the return statement. The same check can be performed with template metaprogramming, or just skipped as it would not compile with an `int`: the `funcToCallAfterAllAddFoos` would not compile... and with that method name the chances of using a class outside of the hierarchy that matches the template requirements are small :P
David Rodríguez - dribeas
@dribeas: Making the factory a `friend` qualifies as a "way around that", thanks :) Derived classes could still accidentally declare a `public` constructor, of course, but there's no preventing that.
Thomas
+4  A: 

I'm not sure this is possible. However, you could redesign this a little bit: give your base class constructor an argument std::vector<Foo> const &foosToBeAdded, and let derived classes pass the correct foos:

class SomeLibraryClass {
  public:
    SomeLibraryClass(std::vector<Foo> const &foosToBeAdded) {
      /* start initialization */
      std::for_each(foosToBeAdded.begin(), foosToBeAdded.end(),
                    std::bind1st(std::mem_fun(&SomeLibraryClass::addFoo), this));
      funcToCallAfterAllAddFoos();
    }
  private:
    void addFoo(Foo const &someFoo) { /* we are a collection of foos */ }
    void funcToCallAfterAllAddFoos() { /* this is now called at the right time */ }
};

class SomeUserClass : public SomeLibraryClass {
  public:
    SomeUserClass() :
      SomeLibraryClass(makeAFooVector())
    {
    }
  private:
    std::vector<Foo> makeAFooVector() { /* return a vector with three Foos */ }
};

The pattern can be extended by letting the SomeUserClass constructor also receive a vector of Foos. It would then add its own Foos to the list before calling the base class constructor.

You could also pass iterators instead of vectors. Left as an exercise.

Thomas
Minor nitpick: `std::for_each` should be used instead of the explicit `for` loop here. +1
Billy ONeal
Thanks, edited. I knew about that, but I wouldn't have gotten it right without trying to compile it first ;)
Thomas
Well, frankly I find the `for` more explicit than the binding stuff... I am waiting for lambdas! Anyway this is clearly the better solution, no work around and no risk to accidentally create a derived class that misbehaves.
Matthieu M.
A: 

Why provide a public addfoo method at all? You say it is all initialization, so let the collection get paassed to the constructor.

Then you can call the nonvirtual functocall from the constructor

Stephen