Recommended Posts

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)

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?

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.

0

Share this post

Link to post

Share on other sites

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)

Share this post

Link to post

Share on other sites

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.

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.

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.

0

Share this post

Link to post

Share on other sites

I have something like that. To make batching easier to implement, I group entities into subsets and have OnEventStart/End() methods surrounding the group. This makes D3D Begin()/End() pairs flow nicely with groups of entities. However, it still leaves the entity hierarchies as described. I certainly will try to do what you are suggesting in another form. I think I can see one way to take advantage of it.

0

Share this post

Link to post

Share on other sites

This topic is 2834 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.