I have an abstract class Parent, which has multiple children and blank functions for interacting with each of these children. Each Child overrides Parent's functions and interacts with other Childs in different ways; i.e. Child1 has different implementations for interact_with(Child1), interact_with(Child2), etc etc.
In Parent, I have a function interact_with(Parent foo). Every Child looking to interact with another Child must pass through this function first. Until now everything is good, but then we run into a problem: after some basic logic has been processed, the Child then needs to know the specific type of its parameter so it can go on and call its own overridden function. At the moment I have this:
Child1* child1 = dynamic_cast<Child1*>(foo);
Child2* child2 = dynamic_cast<Child2*>(foo);
Child3* child3 = dynamic_cast<Child3*>(foo);
if(child1 != nullptr){
interact_with(child1)
}
else if(child2 != nullptr){
interact_with(child2)
}
else if(child3 != nullptr){
interact_with(child3)
}
It works, but it isn't a very good solution. It gets especially bad when I have so many classes. Is this indicative of flawed base design, and if so, how would I improve this?
EDIT: To clarify: I have something like this
//Parent is an abstract class
class Parent
{
void interact_with(Parent* foo){
//this is here because there is a lengthy code segment
//that needs to be run no matter what child interacts
//with which
//afterwards, I need to interact with whatever foo really is
}
virtual void interact_with(Child1* child){*blank*};
virtual void interact_with(Child2* child){*blank*};
virtual void interact_with(Child3) child){*blank*};
};
class Child1 : public Parent
{
virtual void interact_with(Child1* child){*do something*};
virtual void interact_with(Child2* child){*do something else*};
virtual void interact_with(Child3* child){*do something else*};
};
Already.
The #imreal answer using double dispatch is correct. However, the dispatches can be done using virtual member functions instead of a map and function pointers (which is actually similar to the vtable the compiler generates).
The problem is that a single virtual function will not solve the problem, because you really need a double dispatch (i.e. a virtual call regarding both objects, not just the one being called).
See the following working example:
#include <iostream>
class Child1;
class Child2;
class Parent
{
public:
virtual void interact_with(Parent* other) = 0;
virtual void interact_with(Child1* child) {};
virtual void interact_with(Child2* child) {};
};
class Child1 : public Parent
{
public:
virtual void interact_with(Parent* other)
{
other->interact_with(this);
}
virtual void interact_with(Child1* child)
{
std::cout << "Child1 - Child1\n";
}
virtual void interact_with(Child2* child)
{
std::cout << "Child1 - Child2\n";
}
};
class Child2 : public Parent
{
public:
virtual void interact_with(Parent* other)
{
other->interact_with(this);
}
virtual void interact_with(Child1* child)
{
std::cout << "Child2 - Child1\n";
}
virtual void interact_with(Child2* child)
{
std::cout << "Child2 - Child2\n";
}
};
int main()
{
Child1 c1;
Parent* p1 = &c1; // upcast to parent, from p1, we don't know the child type
Child2 c2;
Parent* p2 = &c2;
c1.interact_with(&c2); // single virtual call to Child1 - Child2
p1->interact_with(&c2); // single virtual call to Child1 - Child2
p1->interact_with(p2); // double virtual call to Child2 - Child1 (NB: reversed interaction)
}
It outputs:
Child1 - Child2
Child1 - Child2
Child2 - Child1
Note the last one is reversed. That's because to make the dynamic dispatch using virtual functions on the argument, I have to swap the this pointer with the argument. This is fine if these interactions are symmetric. If they aren't, then I'd suggest to create a wrapper around the most generic one swapping the this and the argument again.
Warning: this solution will break your interfaces. But don't worry, they are already broken ;)
In my opinion your design mistake is following: although all children are "equal" you pick one of them to be responsible for interactions and call a method on it (And if you want 3, 4, ..., N equal children (in an array) to interact simultaneously, which one is responsible?)
If in your application all objects are equally important and no object is responsible for interactions, you should move interactions into free overloaded binary functions:
void interact(Child1* a, Child1* b);
void interact(Child1* a, Child2* b);
...
void interact(Child2* a, Child1* b)
{
interact(b, a); // if order does not matter, reuse another function
}
Clearly, it won't solve the problem of boilerplate code, but at least it could help you to re-think your design and to find a better solution than double dispatch or casting.
Also, depending on functions internals, you could probably reduce writing (but not code size) easily by using template functions instead of overloaded ones.
Using dynamic_cast<> like that is bad design like you said. You should make the function interact_with virtual like this in the declaration.
virtual void interact_with(Parent foo);
This will make the method call use the subclass's implementation of interact_with instead of the parent class's. You can then replace everything you've written with just this.
interact_with(foo);
Here is a pretty good explanation of virtual methods.
What you want is double dispatch
There are many approaches that you might take depending on your requirements. A very generic one is having a simple map of the form Key(type, type) -> Value(function) that associates an argument type pair with the function to be called.
In this case you will need a set of free functions of the type void function(Parent*, Parent*) (one for every combination you need) and a map of the type std::unordered_map<std::pair<TypeId, TypeId>, FunctionType> where TypeId is some form of type identifier with value semantics.
Then you do the dispatch at runtime:
if(map_.find(make_pair(type1, type2)) != map_.end())
map_[make_pair(type1, type2)](obj1, obj2);
Not before registering each function:
map_[make_pair(type1, type2)] = func12;
map_[make_pair(type2, type3)] = func23;
....
Related
I asked this question :
Best Way to Refactor Class Hierarchy
in such a bad way that I was logically forced to accept the perfectly correct answer. My problem is the following :
I have a class CGrandMother having a public method virtual bool Compute() that does
virtual bool Compute()
{
return false;
}
From CGrandMother derives publicly CMother which does not implement Compute. Now from CMother derive publicly C1 and C2 that do implement virtual bool Compute(). Now virtual bool C1::Compute() and virtual bool C2::Compute() respectively do a lot of stuff proper to respectively C1 and to C2, but also a lot of identical stuff proper to CMother. Now there's a class CFamily having as member a pointer to CMother and almost everywhere in the code Compute is called through lines of the form
ptrCMother->Compute();
I want to factor out the common stuff related to CMother done in C1 and C2 so that I wouldn't have to change all those ptrCMother->Compute();. Of course I can create a member function in CMother doing it, and call the latter in bool C1::Compute() and bool C2::Compute(). But...
In c++, if you have B deriving from A, A::dostuff() and B::dostuff() and if p points to a type B then p->dostuff() will execute B::dostuff() by polymorphism. I would like to know if there's an idiom/pattern allowing me to achieve this : "p->dostuff()" will execute "A::dostuff()" or not (according to a bool let's say) and then "B::dostuff()", which does of course not happen in c++ for class member functions that are non constructors etc.
To be clear : base method is not called before its corresponding derived method is called by indirection. Is there an idiom/pattern allowing make base method being called (or not, according to a bool) before its corresponding derived method ?
What's wrong with the solution that you mentioned, consisting in creating a method in the CMother class that is called by its children?
#include <iostream>
#include <memory>
using namespace std;
class CGrandMother
{
private:
virtual bool _Compute()
{
return false;
}
public:
bool Compute()
{
return _Compute();
}
};
class CMother : public CGrandMother
{
protected:
void _CommonStuff()
{
cout << "work common to children" << endl;
}
};
class C1 : public CMother
{
private:
virtual bool _Compute() override
{
_CommonStuff();
cout << "work specific to C1" << endl;
return true;
}
};
class C2 : public CMother
{
private:
virtual bool _Compute() override
{
_CommonStuff();
cout << "work specific to C2" << endl;
return true;
}
};
int main() {
unique_ptr<CMother> c1(new C1);
unique_ptr<CMother> c2(new C2);
c1->Compute();
c2->Compute();
return 0;
}
Notice that I've restrained the access modifiers of my classes:
There is no public virtual function, following the Non-Virtual Interface pattern. A function that is both public and virtual has two jobs: It defines an interface and an implementation, and often ends up being bad at both.
The method _CommonStuff() is protected, so that it is not visible to the rest of the world but still callable by subclasses
Also, you make CMother inherit publicly from CGrandMother, which means that a CMother is a CGrandMother. Is that really true?
Note also that if CMother was the head of the hierarchy, then you could have called _CommonStuff() through its public (but non virtual!) Compute method, and all the subclasses would automatically call _CommonStuff() too. That's one of the great things about this pattern: You can easily make your Compute() method do work that is common to all the subclasses, check invariants, etc
This would look like that: https://ideone.com/vXd4fL
I removed CGrandMother, and CMother is now the head of my hierarchy. In its public method Compute(), I call _CommonStuff(). The children only have to implement _Compute(). _CommonStuff() will be called automatically by all children when they call Compute().
Suppose we have the following:
class Parent {
public:
virtual void run() {
for (int i = 0 ; i < bar.size() ; ++it)
cout << i << "\n" ;
};
protected:
static vector<int> foo() {return vector r({1,2,3,4,5});};
static vector<int> bar;
}
vector<int> Parent::bar = Parent::foo();
Now if I create a child class whose run function would be called externally, how can I redefine the foo function to return something else while still using the parent run function?
Edit: Sorry let me add some more information. Suppose the virtual function run() is a lot of code, all of which is essentially the same. The only difference in the parent and child classes is what values I want specified in the vector bar, so it would seem to be a little wasteful to redefine the virtual function in the child class. However, if you redefine Child::bar, and call Child::run(), the Parent::bar is used since it's defined in the parent class. Is there some way to have the line "vector Parent::bar = Parent::foo();" know in the Child class to use "Child::foo();"?
As usual. Override base virtual function in derived class.
class Parent {
public:
virtual bool run() {return bar;};
static bool foo() {return true;};
static bool bar;
};
class Child: public Parent
{
public:
static bool foo() { return false;};
};
You can then still use base version applying Base:: scope resolution:
int main() {
bool bc = Child::foo();
bool bp = Parent::foo();
std::cout << bc << bp;
return 0;
}
http://ideone.com/TdaNQ5
I am not sure what do you exactly want here. However, you can override the static function like this,
class Child: public Parent
{
public:
static bool foo() {return false;};
};
You really don't say much about your problem, therefore it is hard to distinguish what you need from what is potentially an XY problem.
One potential problem with your architecture is that you have a Parent and a Child classes that share a static variable bar yet you seem to initialize them differently for Parent and Child classes. However, there is only one bar that is shared both by Parent and Child objects, independently of who wrote to it last.
So, what do you expect when both a Parent and a Child objects are used simultaneously? The answer you look for depends on your answer on that one. In particular, if your answer is 'it is not designed to have Parent and Child objects operate simultaneously', then both classes should definitely not share a static variable.
I got a function that have two base class pointers and depending on the subclass, other functions should be called...
Like this:
void function(A* a, A* a2){
if (typeid(*a).name() == "B"){
if(typeid(*a2).name() == "C"){
otherFunction();
}
if(typeid(*a2).name() == "D"){
otherFunction2();
}
}
}
However, there's a whole buncha problems:
1) I've read that typeid.name yield different result depending on the compiler and therefore I don't want to use it.
2) I've considered creating an instance of "B" and instead writing if(typeid(*a2) == typeid(instanceOfB)) but that would be a lot of work since there are plenty of constructor arguments...
3) I've also considered using dynamic_cast but some subclasses look like this:
A <-- B <-- C
so if if I wanted to check if the argument is B with dynamic cast, it would pass even if the argument is in fact C because C inherits from B
Edit: It seems I'll have to reconsider the design but since many have stated the design is flawed I'll quickly explain what my train of thought:
There's a window. Several different objects are located inside the window and move around, a game. This function was supposed to function as a collision detection. Like this:
Go through all objects on the screen, check if the have collided. Take the two collided objects as arguments and call this function.
This function looks up a buncha different collisions like "if a is "an arrow" and a2 is "a bandit" then do some stuff but if a2 is "a tree" instead, do this instead!
Wouldn't it be better to have some virtual methods in A that do nothing by default and are overwritten by some of its inheriting classes?
class A {
public:
virtual void method(A *a2) {
}
virtual void otherMethod() {
}
};
class B : public A {
public:
virtual void method(A *a2) {
a2->otherMethod();
}
};
class C : public B {
public:
virtual void otherMethod() {
// do your C stuff here
}
};
class D : public A {
public:
virtual void otherMethod() {
// do your D stuff here
}
};
Would this achieve the things you are trying to do?
CLOS has a neat concept of :before, :after, and :around methods.
The :before methods are called before the primary method.
The :after methods are called after the primary method.
The :around methods are called around the :before+primary+:after sequence.
The :before, :after, and :around methods are chained rather than overridden. Suppose both a parent and child class define a foo method and :before foo method. The child's foo method overrides the parent's foo method, but both the child's and parent's :before foo methods are called before this overridden method is called.
Python decorators provide something similar to the CLOS :around methods. There is nothing like this in C++. It has to be hand-rolled:
class Child : public Parent {
virtual void do_something (Elided arguments) {
do_some_preliminary_stuff();
Parent::do_something (arguments);
do_some_followup_stuff();
}
};
Downsides:
This is an anti-pattern to some people.
It requires me to be explicit in specifying the parent class.
It requires extenders of my classes to follow the same paradigm.
What if I need to call the grandparent because the parent doesn't override do_something, and what about multiple inheritance?
It doesn't quite capture the CLOS concept.
I found these concepts to be quite handy way back when I used Flavors (predecessor to CLOS). I've used the above workaround in a few places, and a few have challenged it as an anti-pattern. (Others have emulated it elsewhere, so the derision is not universal.)
The question: Is this considered an anti-pattern in C++, and are there better workarounds?
You can get the basics of this quite nicely using (std/boost)::shared_ptr. For details see here : http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/sp_techniques.html#wrapper
Getting the inheritance behaviour you mention just requires the prefix/suffix functions to call the prefix/suffix functions in the parent class.
This is what I could do, but it's still a bit ugly.
Basically I put the actual work in a separate hook so you don't have call the pre/post hooks in the processing method. In the inheritance chain you have total control both on whether you want to add pre/post hooks and the ordering of the hook calls (call the parent's hook before or after the child's hook).
#include <iostream>
#define C(s) std::cout << s << std::endl;
class Parent {
public:
virtual void do_something(int arg) {
do_some_pre_hook();
do_some_hook(arg);
do_some_post_hook();
}
virtual void do_some_pre_hook() {
C("parent pre_hook");
}
virtual void do_some_post_hook() {
C("parent post_hook");
}
virtual void do_some_hook(int arg) {
//this is where you actually do the work
}
};
class Child : public Parent {
public:
typedef Parent super;
virtual void do_some_pre_hook() {
super::do_some_pre_hook();
C("Child pre_hook");
}
virtual void do_some_post_hook() {
super::do_some_post_hook();
C("Child post_hook");
}
};
class GrandChild : public Child {
public:
typedef Child super;
virtual void do_some_pre_hook() {
super::do_some_pre_hook();
C("GrandChild pre_hook");
}
virtual void do_some_post_hook() {
super::do_some_post_hook();
C("GrandChild post_hook");
}
virtual void do_some_hook(int arg) {
//this is where you actually do the work
C("GrandChild hook");
}
};
int main() {
GrandChild gc;
gc.do_something(12);
}
Note: Ideally you would use an AOP c++ compiler or compiler extension for a task like that, but the last time I tried it it wasn't quite stable...
I'm not claiming this is equivalent or comparable to what other languages do, but I think the Non Virtual Interface idiom is applicable for your problem:
class parent {
public:
void foo()
{
before_foo();
do_foo();
after_foo();
}
protected:
// you can make those pure virtual with an implentation, too
virtual void before_foo() { ... }
virtual void do_foo() { ... }
virtual void after_foo() { ... }
};
class child: public parent {
protected: // or private
void before_foo() { ... }
void do_foo() { ... }
// must provide a dummy after_foo that delegates to parent::after_foo
// if it is pure virtual in the parent class
};
When calling p.foo(), the most derived before_foo, after_foo and do_foo are always called.
So, I have a list of base class pointers:
list<Base*> stuff;
Then, at some point one of the objects will look through all other objects.
Base * obj = ...; // A pointer from the 'stuff'-list.
for (list<Base*>::iterator it = stuff.begin(); it != stuff.end(); it++)
{
if (obj == *it)
continue;
// Problem scenario is here
obj->interact(it);
}
What I want to achieve is that depending on what derived typeobj and *it are, they will interact differently with each other, i.e. DerivedA will destroy itself if it's interacting with DerivedB, but only if DerivedB has set the property bool c = true;. So something like:
struct Base
{
virtual void interact(Base * b); // is always called
};
struct DerivedA : public Base
{
virtual void interact(Base * b){} // is never called
virtual void interact(DerivedB * b) // is never called
{
if (b->c)
delete this;
}
};
struct DerivedB : public Base
{
bool c = false;
virtual void interact(Base * b){} // is never called
virtual void interact(DerivedA * a) // is never called
{
c = true;
}
};
// and many many more Derived classes with many many more specific behaviors.
At compile time, they are both Base-pointers and will not be able to call each other and expect the type to magically appear. If this was a one way relation, i.e. I knew what type of one of them, I could use the Visitor pattern. I believe I should use some kind of Mediator pattern but can't really figure out how since the mediator too will hold Base-pointers and thus it won't make a difference.
I haven't got a clue on how to continue... anyone?
Background:
I'm creating a game, this problem originates from the Room class who keeps track of it's contents, i.e. what GameObjects are currently in the room.
Sometimes, an object moves (for example, the player). The room will then loop over all objects that are on the soon-to-be-moved-upon floor tile (the loop above) and will check if the objects will interact with eachother.
For example, if it's a Troll the Player would want to hurt it. Or he would just like to hurt any Character (both Troll and Player are derived from Character) that originates from any another "team" (which can be accessed from the function getAlignment(), which all Characters implement).
If you can, grab a copy of "More Effective C++", and have a look at item #31 which is about implementing multiple dispatch, which is basically what you're looking for here. Meyers discusses several approaches to the problem and their various trade-offs. (He even uses a game as an example.)
Perhaps the best advice he gives, however, is to try and redesign your code to avoid requiring this facility. In the text, a non-member function approach is also explored, which has the added bonus of eliminating the question of to which object each function describing an interaction should belong.
I think your suggested idea (with the Base::interact) function is almost complete. It seems that the only missing part is this:
In your Base, you need to have all the interact overloads for the sub-types. Consider this extension to your Base structure:
struct DerivedA;
struct DerivedB;
struct Base
{
virtual void interact(Base * b); // *<->Base interaction
virtual void interact(DerivedA * da); // *<->DerivedA interaction
virtual void interact(DerivedB * db); // *<->DerivedB interaction
};
This is a painful thing about implementing double-dispatch in C++: if you add a new sub-type, you have to touch the base of the hierarchy.
you will need to implement all possible combinations of types interacting with each other as virtual functions on top of hierarchy.
Here's an example that tests all possible interactions:
#include<iostream>
void say(const char *s){std::cout<<s<<std::endl;}
struct DerivedA;
struct DerivedB;
struct Base{
virtual void interact(Base *b) = 0;
virtual void interactA(DerivedA *b) = 0;
virtual void interactB(DerivedB *b) = 0;
};
struct DerivedA : public Base
{
virtual void interact(Base *b){
b->interactA( this );
}
virtual void interactA(DerivedA *b){
say("A:A");
}
virtual void interactB(DerivedB *b){
say("A:B");
}
};
struct DerivedB:public Base{
virtual void interact(Base *b){
b->interactB( this );
}
virtual void interactA(DerivedA *b){
say("B:A");
}
virtual void interactB(DerivedB *b){
say("B:B");
}
};
void interact(Base *b1,Base *b2){
b1->interact( b2 );
}
main(){
Base *a = new DerivedA;
Base *b = new DerivedB();
interact(a,b);
interact(b,a);
interact(a,a);
interact(b,b);
}
First: Why do you use struct instead of class?
Second: If you use class instead of struct you could (must) do something like this:
class Base
{
virtual void interact(Base * b); // see the VIRTUAL word (explained down)
};
class DerivedA : public Base
{
virtual void interact(DerivedB * b)
{
if (b->c)
delete this;
}
};
class DerivedB : public Base
{
bool c = false;
virtual void interact(DerivedA * a)
{
c = true;
}
};
Using virtual keyword is wath you need (I guess). If you define a method as virtual you are telling "Hey! this maybe has been override someplace" so.. when you code this:
DerivedA* a = new DerivedA();
DerivedB* b = new DerivedB();
a.interact(b); // here instead of calling Base::interact(Base*) call the override method in DerivedA class (because is virtual)
EDIT:
Forget that answer.. (didn't see the comment of the virtual)
EDIT 2:
Please, see catwalk and Frerich Raabe answers.
Your interact() functions don't have the same signature: In the derived classes they should also be
virtual void interact(Base * b);
The virtual is optional, of course, but for clarity I'd put it in there.
To find out whether DerivedA::interact() should do something with it's parameter, you can implement another virtual functions in your base class:
virtual canDoX(Base * b);
virtual canDoY(Base * b);
Then in the derived implementations it could look like this:
// DerivedA
void interact(Base * b)
{
if (b->canDoX() && b->c)
delete this;
}
// DerivedB
void interact(Base * b)
{
if(b->canDoY())
c = true;
}
Update:
Since you liked Frerich Raabe's answer, let me explain why I think my approach is a bit better.
Following his advice, one has to create an interact() method for each derived class in the base and all other derived classes that can interact with a certain class.
With my solution one would have to add methods for certain properties, that can also be combined.
If you have a Troll it would return true in its canBeKilled() method. An apple canBeEaten() and a tasty wild animal canBeKilled() and then canBeEaten().
If you can combine the properties, you have to add fewer functions.
Furthermore: If the troll drank some elixir making it invulnerable for a period of time, it returns canBeKilled() == false and that's it. You don't have to check the isInvulnerable() flag in each other interacting class.
I think your problem is well discussed in
Scott Meyer's Effective C++ which is like as follows:
Rule : Don't try access array of derived class objects using base class pointer -->the result would be undefined.
I will give you an example of it:
struct Base{
virtual void print() { //in base }
virtual ~Base() {} //
}
struct Derived : public Base {
virtual void print(){ //in derived }
}
void foo(Base *pBase,int N)
{
for(int i=0; i<N ; i++)
pBase[i].print(); // result will be undefined......
}
int main()
{
Derived d[5];
foo(&d,5);
}
The reason for it such behaviour is that compiler find next elements at the jump of sizeof(Base) bytes....
I think you got my point....