23

I have some events like this

class Granpa // this would not be changed, as its in a dll and not written by me
{
public:

   virtual void onLoad(){}

}

class Father :public Granpa // my modification on Granpa
{
public:

    virtual void onLoad()
    {
       // do important stuff
    }

}

class Child :public Father// client will derive Father
{

   virtual void onLoad()
   {
       // Father::onLoad(); // i'm trying do this without client explicitly writing the call

       // clients code
   }
}

Is there a way to force calling onLoad without actually writing Father::onLoad()?

Hackish solutions are welcome :)

Amit Tomar
  • 4,800
  • 6
  • 50
  • 83
mikbal
  • 1,168
  • 1
  • 16
  • 27
  • 4
    I don't understand why this is a problem. You want to explicitly do something, so you need to explicitly say so in the code... – Oliver Charlesworth Mar 15 '12 at 16:54
  • 2
    Is it a bit lazy not to add a line of code to do something that you want to occur explicitly? – Ed Heal Mar 15 '12 at 16:56
  • Since the same problem is not solved in i.e. MFC handlers (you always need to explicitly call CDialog::OnInitDialog() from your CMyDialog::OnInitDialog()), I think you can just require user to do that. – Mikhail Mar 15 '12 at 16:56
  • 1
    I agree with @OliCharlesworth, I hardly see how this is a problem. If the client wants to call it, he will explicitly call it. – ApprenticeHacker Mar 15 '12 at 16:57
  • 1
    if there is no solution to force the call, i'll add in documentation that they should call it. it's better to not over complicate things for the client. – mikbal Mar 15 '12 at 16:58
  • I'd much, much rather go with an explicit designation than a hackish solution. You don't want to give the next person reading your code (which could be you in six months) any additional difficulty figuring out what the code does. – David Thornley Mar 15 '12 at 16:59
  • @David Thornley Non-virtual interface isn't hackish in any way though and solves the problem if I understand it right. – Mark B Mar 15 '12 at 17:06
  • I know this post is old, but I'm also looking for something like this. My reasons are that not implementing the base class later could cause various risks in how the method is called. It is essentially "safer" to force the derived class implementation to call the method from the base class, similarly to how the constructor forces it already. In my specific case, I want an abstract class which calls its version of a mouse press event first, and derived classes do their own. There's little to no good reason why the base method shouldn't get called whenever the derived method is called. – Osama Kawish Sep 30 '19 at 14:50

4 Answers4

35

If I understand correctly, you want it so that whenever the overriden function gets called, the base-class implementation must always get called first. In which case, you could investigate the template pattern. Something like:

class Base
{
public:
    void foo() {
        baseStuff();
        derivedStuff();
    }

protected:
    virtual void derivedStuff() = 0;
private:
    void baseStuff() { ... }
};

class Derived : public Base {
protected:
    virtual void derivedStuff() {
        // This will always get called after baseStuff()
        ...
    }
};
Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • 2
    Also known as Non-virtual interface (although I've always known it as template method pattern). – Mark B Mar 15 '12 at 17:04
  • derivedStuff can be private in both classes too. – Dan Mar 15 '12 at 17:08
  • 2
    A good explanation can also be found here http://www.gotw.ca/publications/mill18.htm – pmr Mar 15 '12 at 17:09
  • 1
    as said in my response, in his case, GrandPa is external code & foo (onLoad) is imposed to be virtual. so nothing prevents Child to override it. – dweeves Mar 15 '12 at 17:14
  • @dweeves new virtual onLoaded will be documented but old onLoad will not. there doesnt seem to be better solution for this. – mikbal Mar 15 '12 at 17:24
  • Base::derivedStuff() should be protected, not private, otherwise you can't reimplement it in Derived. – Aurélien Gâteau Jul 03 '12 at 14:21
  • I find this pattern breaks down with three levels of inheritance, unless you can continue to come up with meaning full names for the same event. – Aaron Wright Mar 22 '19 at 22:39
3

As suggested above but applied to your case.

class Father :public Granpa // my modification on Granpa
{

public:

    virtual void onLoad()
    {
       // do important stuff
       onLoadHandler();
    }
    virtual void onLoadHandler()=0;
}

class Child :public Father// client will derive Father  
{

   virtual void onLoadHandler()
   {

       // clients code
   }
}

However, nothing can prevent Child to override onLoad since c++ has no final keyword and Granpa onLoad is itself virtual.

dweeves
  • 5,525
  • 22
  • 28
3

Well, there is no widely known, recognized way to do this. If there had been, GUI libraries using events and signals would probably have implemented it. However there are other solutions to your problem.

You could implement a signal - event connection, using boost.Signals, sigslot or something of your own making. As GTK+ does:

g_signal_connect(my_wdg, "expose-event", G_CALLBACK(my_func), NULL);

gboolean my_func(...)
{
    // do stuff 
    return FALSE; /* this tells the event handler to also call the base class's slot */
}

In a less C-centric way, this could be implemented along these lines:

/* In Granpa */
/* typedef a functor as 'DerivedEventHandler' or use a boost::function */
std::vector< DerivedEventHandler > handlers;

void connect(DerivedEventHandler event) { handlers.push_back(event); }

/* in loop */
while (! iter = handlers.end() ) /* call event */

/* In constructor of Father */
this->connect( this->OnLoad );

/* In constructor of Child */
this->connect( this->OnLoad );

/* and so on... in all derived classes  */
ApprenticeHacker
  • 21,351
  • 27
  • 103
  • 153
-1

If the object in question is small and cheap to copy, simply call the base class' copy constructor, i.e. BaseClass(*derived_class_object).method()

  • Probably not what OP wanted, since he asked how to do it wihtout explictly writing the baseClass function call, which you'd have to do with this approach as well. – Haatschii Feb 03 '13 at 14:07