1

So I'm working on a personal project (trying to get better at c++), and I'm trying to get this working:

I have an ABC class A with a pure virtual function interactWith(A* target);

I then have two derived classes, class B and class C.

However, class B must interactWith class C differently than with another class B

I found one way of doing this with an if/else and a virtual getType() in the ABC, but I was curious if there was a more elegant way or if I'm just doing something very stupid, and if I am doing something stupid (which is very possible), where would I begin searching for a better solution (i.e. a more appropriate design pattern)

Please note: I'm not using boost, and I'd rather avoid it for now, and start learning it when I'm actually good at programming

Any help you could provide would be welcome. Please and thankyou

Something I should note: classes B and C will (should) only be visible via an A*

1
  • "However, class B must interactWith class C differently than with another class B" - Why? Have you considered polymorphic functions? Commented Jun 7, 2012 at 0:30

4 Answers 4

2

What you are trying to implement is called double dispatch: a function that behaves as virtual with respect to two objects.

There are several ways to implement it, one of the more common being the use of visitor pattern.

Scott Meyers has an excellent chapter on implementing double dispatch (Item #31 in his "More Effective C++" book). He starts with the discussion of the visitor pattern, and then proceeds to a very nice implementation with RTTI.

Sign up to request clarification or add additional context in comments.

2 Comments

Better than my answer, and a few seconds earlier, too…
Thanks for the references. They were very helpful
2

You almost never want to use type-switching. Dynamic casting is a little better, but still to be avoided if possible.

A better alternative is to turn things around so you can use the virtual dispatch mechanism again, often called "double dispatch" or "simulating multi-methods". It will look something like this:

struct B;

struct A { 
  virtual void interactWith(A* target); 
  virtual void interactWithB(B* target);
};

struct B : A {
  virtual void interactWith(A* target) {
    target->interactWithB(this);
  }
  virtual void interactWithB(B* lhs) {
    // B vs. B stuff goes here, but with lhs and this in place of this and target
  }
};

struct C : A {
  virtual void interactWith(A* target) {
    // C vs. anything stuff goes here
  }
  virtual void interactWithB(B* lhs) {
    // B vs. C stuff goes here, again backward
  }
};

1 Comment

+1 Well, you've got some code going here, which is a good reason to be a few seconds late :)
0

Use dynamic_cast

C* cTarget = dynamic_cast<C*>(target);
if(cTarget == NULL)
{
    //cTarget is not a C
}
else if(cTarget)
{
    //cTarget is a C
}

dynamic_cast does some fancy stuff(I'm not sure what it does) to make sure that the cast is valid, and if it is not, it returns NULL.

1 Comment

This is generally the wrong way to do it. Also, you really shouldn't be relying on dynamic_cast unless you have at least some vague understanding of the "fancy stuff" it does (which only involves checking the rtti in cases of single inheritance, but more when multiple inheritance graphs get involved).
0

Ideally, encapsulate the behavior that needs to be different between a B and a C when interacting with it, and put it into another virtual method that you call on target -- there will then be different implementations of that method in B and C as appropriate.

If the above gets too confused and too scattered, that's an indication that you've chosen the wrong abstractions to be your objects. You might be better off scrapping the A/B/C class hierarchy and dividing up your program into a different hierarchy, but without a more concrete description of what you are trying to do its impossible to say. Premature abstraction (along with premature optimization) is one of the key mistakes inexperienced programmers often make.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.