[C++] Parent to derived method

Started by
9 comments, last by zyrolasting 14 years, 1 month ago
Each derivative of my base class updates the state of the object once per frame though one virtual method. I need to invoke parent implementations before derived ones. (Imagine a generic camera object needing to update before the FirstPersonCamera object)
#include <iostream>
using namespace std;

struct A { virtual void foo() { cout << "Hello, "; } };

struct B : A
{
	B() { foo(); }

	void foo()
	{
		// Need parent impl first
		__super::foo();
		cout << "World!" << endl;
	}
};

int main()
{
	B b; // Hello, World!
	return 0;
}
Note that while the code above does what I want, I don't want to explicitly call parent implementations. Is it possible to automate calls from the top level class down to the most derived?
Advertisement
Quote:Original post by zyrolasting
Is it possible to automate calls from the top level class down to the most derived?


No.
Can I get details on why?
Quote:Original post by zyrolasting
Can I get details on why?


How do you expect to do it?

C++ provides a method of calling the parent class's implementation *if you need to*. There is no way to make it so that the parent class's implementation is called automatically. What if it has some sort of parameters, or a special return value?
Quote:Original post by zyrolasting
Can I get details on why?


That's the way language is designed.

One problem is multiple inheritance (diamond inheritance in particular). In which order are the functions called?

A better solution:
struct Base {  void update() {    before();    specific_update();    after();  }protected:  virtual void specific_update() = 0;private:  void before();  void after();};
This is impossible. It cannot be done, period... and beyond that, should not be done. Keeping that firmly in mind...

class A{protected:  class BaseToken // only A can create this  {  private:    BaseToken() { }    friend class A;  };public:  // override it if you like, but you've gotta get a BaseToken from somewhere  virtual BaseToken f() {     // doStuff();    return BaseToken();  }};class B : public A{public:  virtual BaseToken f()  {    BaseToken b = A::f();    // doOtherStuff();    return b;  }};


Incidentally, this is still prone to extreme circumvention measures: B could cache the token the first time around, then reuse it for subsequent invocations without calling the base function. Nevertheless, it does have one significant advantage over the inversion method Antheus described: With some modifications, it can enforce a call chain having more than two levels.
There is only one method I wish to do this for, and the return codes merely add to a counter. It didn't seem hard to do at first. I managed to automate calls from parent to child, although I do need to allocate an instance of every object type once and need to know the very method beforehand. (which I do). There's just no way to improve on the below, huh? (Dependant on Loki typelist)

#include <iostream>#include <typelist.h>using namespace std;using namespace Loki;struct A{	virtual void foo()	{		cout << "Hello, ";	}};struct B : A{	void foo()	{		cout << "World!" << endl;	}};template<class TList, class F>struct automater;template<class H, class T, class F>struct automater<Typelist<H,T>,F>{	automater()	{		H h;		F f = &H::foo;		(h.*f)();		automater<T,void (T::Head::*)()> n;	}};template<class H, class F>struct automater<Typelist<H,NullType>,F>{	automater()	{		H h;		F f = &H::foo;		(h.*f)();	}};int main(){	automater<TYPELIST_2(A,B),void (A::*)()>();	system("pause");	return 0;}
I'm not sure what problem that code snippet is trying to solve. Obviously if you're willing to just write out every path down the inheritance chain to derived classes (aka your typelist down there), there's no need to automate anything. Just have a function that calls A::foo and then B::foo.
My object hierarchies realistically can go several levels.

I.E.

Entity -> Enemy -> Normal -> Goomba
Entity -> Enemy -> Boss -> Bowser

Each derivative updates the object state appropriately. I would use more normal methods and drop this model altogether if I wasn't so damned tired of babysitting a Direct3D9 device.

The largest hierarchy I ever had was 5 levels, and each derivative needed to call a parent implementation. It's easy to see why I would want to make something generic out of this.

So, I need to call parent implementations explicitly. Alright. Thanks for your help.
Quote:Original post by zyrolasting
There's just no way to improve on the below, huh? (Dependant on Loki typelist)


It's one facet of fundamental problem with OOP, it doesn't model certain things well.

The problem here isn't related to polymorphism or inheritance, but about your particular design not being able to model the domain well.

The actual requirements here require function prolog and epilogue. Without all the template mess, your actual requirements are (most likely):
prolog();func();epilogue();
, but where such calls may be nested. This illustrates the order much better - there is no reason compiler should assume that one prolog must be called before another.

With typelists you don't really need, or want polymorphism, especially with value types, especially with this type of processing. Typelists know concrete type of each list member, so run-time polymorphism is redundant. Your case seems to be only using it to establish the previous concept.

OO works well with opaque interfaces: foreach (IFoo : foos) foo->something();

Anything else is effectively trying to subvert the mechanism, and relying on parent functions is discouraged since it breaks this. There have been various arguments that inherited members should never have access to anything but public interface, making such calls impossible in first place.

So instead consider reorganizing the above into concrete and strong interface:
struct A {  void prologa();  void epiloguea();  virtual void update();};struct B : A{  void prologb();  void epilogueb();    virtual void update(); // override};struct C : B {  void prologc();  void epiloguec();    virtual void update(); // override};


This may seem redundant, but as far as design goes, it prevents many fallacies that occur. It does require you to call a specific function, but is cleaner in the long run, since it allows arbitrary inheritance without obscuring true intent.

Java's super, as trivial as it may seem, needs to enforce considerable and annoying constraints on when and how super may be called to avoid obscure (but surprisingly common and abusable) corner cases.

Quote:The largest hierarchy I ever had was 5 levels, and each derivative needed to call a parent implementation


As mentioned, this is considered a "code smell", even in which Java has much simpler inheritance rules and many more guarantees. If you need to reuse functionality, consider exporting that into separate functions, and then call them directly. Unlike Java, this can be done somewhat simpler and perhaps even cheaper in C++. Free functions are often preferred, following the public-interface-only rule.

This type of calling the parent also wreaks havoc on dependencies and coupling, since calling things down the hierarchy can either break, or introduce expectations of invariants. When A<-B<-C and A<-B<-D are involved, changing B can break C but not D, meaning the entire dependency is coupled in a very undesirable way, since changes to C are seemingly unrelated to D.

This topic is closed to new replies.

Advertisement