views:

175

answers:

4

Hi all,

In C++ an interface can be implemented by a class with all its methods pure virtual.

Such a class could be part of a library to describe what methods an object should implement to be able to work with other classes in the library:

class Lib::IFoo
{
    public:
        virtual void method() = 0;
};

:

class Lib::Bar
{
    public:
        void stuff( Lib::IFoo & );
};

Now I want to to use class Lib::Bar, so I have to implement the IFoo interface.

For my purposes I need a whole of related classes so I would like to work with a base class that guarantees common behavior using the NVI idiom:

class FooBase : public IFoo // implement interface IFoo
{
    public:
        void method(); // calls methodImpl;

    private:
        virtual void methodImpl();
};

The non-virtual interface (NVI) idiom ought to deny derived classes the possibility of overriding the common behavior implemented in FooBase::method(), but since IFoo made it virtual it seems that all derived classes have the opportunity to override the FooBase::method().

If I want to use the NVI idiom, what are my options other than the pImpl idiom already suggested (thanks space-c0wb0y).

+2  A: 

Commonly, the reason for using the NVI (sometimes also called "Template Method") is that derived classes should only change a part of the base class' behavior. So what you do is this:

class base {
  public:
    void f()
    {
      // do something derived classes shouldn't interfere with          
      vf();
      // do something derived classes shouldn't interfere with          
      vg();
      // do something derived classes shouldn't interfere with          
      vh();
      // do something derived classes shouldn't interfere with          
    }
  private:
    virtual void vf(); // might be pure virtual, too
    virtual void vg(); // might be pure virtual, too
    virtual void vh(); // might be pure virtual, too
};

Derived classes can then plug into f() at the spots they are meant to and change aspects of f()'s behavior, without messing up its fundamental algorithm.

sbi
Completely true, but how can I get the base class to implement an interface without losing the guarantees (about the order of execution of vf, vg and vh for example) that my template method offers?
andreas buykx
@andreas: I've answered to your comment to Michael's answer. I suggest you extend your question so that it describes a little better what you want to do. From what I understand, maybe mix-ins or policies might be what you're looking for.
sbi
NVI and Template Method are completely different concepts; though NVI is how Template Method is typically implemented. You could just as simply have a Template Method that uses a strategy object for it's virtuals, and you could just as simply have an NVI pattern that's not for the Template Method pattern.
Billy ONeal
+3  A: 

I think you've got your NVI pattern around the wrong way: http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface

Not sure if that solves your issue though.

class IFoo
{
    public:
       void method() { methodImpl(); }
    private:
       virtual void methodImpl()=0;
};

class FooBase : public IFoo // implement interface IFoo
{
    private:
        virtual void methodImpl();
};

Here's an example of why you might do this using a reader that reads from XML and another from DB. Note that common structure is moved into the NVI readFromSource, while non-common behaviour is moved into the private virtual getRawDatum. This way logging and error checking is only needed in the one function.

class IReader
{
  public:
    // NVI
    Datum readFromSource()
    {
       Datum datum = getRawDatum();
       if( ! datum.isValid() ) throw ReaderError("Unable to get valid datum");
       logger::log("Datum Read");
       return datum;
    }
  private:
    // Virtual Bits
    Datum getRawDatum()=0;
};

class DBReader : public IReader
{
  private:
    Datum getRawDatum() { ... }
};

class XmlReader : public IReader
{
   private:
     Datum getRawDatum() { ... }
};
Michael Anderson
I would like to work with an interface class that *only* prescribes the methods any implementation of that interface should offer, and a base class that guarantees some commonality in the behavior of its derived classes by using the NVI idiom (aka template method). I could have two completely different base classes, one that interfaces with an XML file, and one that interfaces with a RDBMS for example. They implement IFoo, and have to guarantee some commonality in behavior of derived classes.
andreas buykx
@andreas: In C++, interfaces are described by using (possibly abstract) base classes which declare (possibly pure) virtual functions. Derived classes then implement those virtual functions by overriding them. Any virtual member function of the base class can be overridden in _any_ derived classes. Therefor the NVI can only be implemented in the _base_ class, by implementing _non-virtual_ methods. If you want a two-layer approach, simple NVI won't work, since classes derived from the common base classes (which derive from the interface) can override all the interface's virtual functions.
sbi
@andreas I've added an example that does what you describe in your comment. Hope that makes sense. I think you want more than this though .. but I'm not sure what exactly. Maybe you should extend your question further with a full example of 1) What you'd like to be able to do, and/or 2) What is going wrong with the normal NVI?
Michael Anderson
A: 

You could use the pimpl-idiom to achieve this:

class IFoo
{
    public:
        IFoo( boost::shared_ptr< IFooImpl > pImpl )
            : m_pImpl( pImpl )
        {}

        void method() { m_pImpl->method(); }
        void otherMethod() { m_pImpl->otherMethod(); }
    private:
        boost::shared_ptr< IFooImpl > m_pImpl;
};

class IFooImpl
{
    public:
        void method();
        virtual void otherMethod();
};

Now others can still subclass IFooImpl and pass it to IFoo, but they cannot override the behavior of method (they can override otherMethod). You can even make IFooImpl a direct subclass of IFoo and use enable_shared_from_this to initialize IFoo correctly. This is just the gist of the method. There are many ways to tweak this approach. For instance you can use the factory-pattern to make sure IFoos are created correctly.

Hope that helps.

Space_C0wb0y
Hmm.. this seems like a lot of overhead and machinery to avoid having a private virtual function....
Billy ONeal
The problem is that any virtual function, even the private ones, can be overriden by subclasses. This option does have a lot of boilerplate, true, but it is bulletproof. So it is a trade-off.
Space_C0wb0y
A: 

It may be confusing that once a method is declared as virtual in a base class, it automatically becomes virtual in all derived classes, even if the virtual keywords is not used there. So in your example, both methods of FooBase are virtual.

... to deny derived classes the possibility of overriding the common behavior implemented in FooBase::method()...

If you can get rid of IFoo, and just start the hierarchy with FooBase with a non-virtual method, that would do it. But it looks like you want to allow direct children of IFoo to override method(), but to prevent children of FooBase to override it. I don't think that's possible.

DS