Open main menu
Home
Random
Recent changes
Special pages
Community portal
Preferences
About Wikipedia
Disclaimers
Incubator escapee wiki
Search
User menu
Talk
Dark mode
Contributions
Create account
Log in
Editing
Double dispatch
(section)
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
===C++=== At first glance, double dispatch appears to be a natural result of [[function overloading]]. Function overloading allows the function called to depend on the type of the argument. Function overloading, however, is done at compile time using "[[name mangling]]" where the internal name of the function encodes the argument's type. For example, a function <code>foo(int)</code> may internally be called ''{{mono|__foo_i}}'' and the function <code>foo(double)</code> may be called ''{{mono|__foo_d}}''. Thus, there is no name collision, and no virtual table lookup. By contrast, dynamic dispatch is based on the type of the calling object, meaning it uses [[virtual functions]] (overriding) instead of [[function overloading]], and does result in a vtable lookup. Consider the following example, written in [[C++]], of collisions in a game: <syntaxhighlight lang="cpp"> class SpaceShip {}; class ApolloSpacecraft : public SpaceShip {}; class Asteroid { public: virtual void CollideWith(SpaceShip&) { std::cout << "Asteroid hit a SpaceShip\n"; } virtual void CollideWith(ApolloSpacecraft&) { std::cout << "Asteroid hit an ApolloSpacecraft\n"; } }; class ExplodingAsteroid : public Asteroid { public: void CollideWith(SpaceShip&) override { std::cout << "ExplodingAsteroid hit a SpaceShip\n"; } void CollideWith(ApolloSpacecraft&) override { std::cout << "ExplodingAsteroid hit an ApolloSpacecraft\n"; } }; </syntaxhighlight> If you have: <syntaxhighlight lang="cpp"> Asteroid theAsteroid; SpaceShip theSpaceShip; ApolloSpacecraft theApolloSpacecraft; </syntaxhighlight> then, because of function overloading, <syntaxhighlight lang="cpp"> theAsteroid.CollideWith(theSpaceShip); theAsteroid.CollideWith(theApolloSpacecraft); </syntaxhighlight> will print, respectively, <code>Asteroid hit a SpaceShip</code> and <code>Asteroid hit an ApolloSpacecraft</code>, without using any dynamic dispatch. Furthermore: <syntaxhighlight lang="cpp"> ExplodingAsteroid theExplodingAsteroid; theExplodingAsteroid.CollideWith(theSpaceShip); theExplodingAsteroid.CollideWith(theApolloSpacecraft); </syntaxhighlight> will print <code>ExplodingAsteroid hit a SpaceShip</code> and <code>ExplodingAsteroid hit an ApolloSpacecraft</code> respectively, again without dynamic dispatch. With a reference to an <code>Asteroid</code>, dynamic dispatch is used, and this code: <syntaxhighlight lang="cpp"> Asteroid& theAsteroidReference = theExplodingAsteroid; theAsteroidReference.CollideWith(theSpaceShip); theAsteroidReference.CollideWith(theApolloSpacecraft); </syntaxhighlight> prints <code>ExplodingAsteroid hit a SpaceShip</code> and <code>ExplodingAsteroid hit an ApolloSpacecraft</code>, again as expected. However, the following code does not work as desired: <syntaxhighlight lang="cpp"> SpaceShip& theSpaceShipReference = theApolloSpacecraft; theAsteroid.CollideWith(theSpaceShipReference); theAsteroidReference.CollideWith(theSpaceShipReference); </syntaxhighlight> The desired behaviour is to bind these calls to the function that takes <code>theApolloSpacecraft</code> as its argument, as that is the instantiated type of the variable, meaning the expected output would be <code>Asteroid hit an ApolloSpacecraft</code> and <code>ExplodingAsteroid hit an ApolloSpacecraft</code>. However, the output is actually <code>Asteroid hit a SpaceShip</code> and <code>ExplodingAsteroid hit a SpaceShip</code>. The problem is that, while virtual functions are dispatched dynamically in C++, function overloading is done statically. The problem described above can be resolved by [[simulating]] double dispatch, for example by using a [[visitor pattern]]. Suppose the existing code is extended so that both <code>SpaceShip</code> and <code>ApolloSpacecraft</code> are given the function <syntaxhighlight lang="cpp"> virtual void CollideWith(Asteroid& inAsteroid) { inAsteroid.CollideWith(*this); } </syntaxhighlight> Then, while the previous example still does not work correctly, reframing the calls so that the spaceship is the agent gives us the desired behaviour: <syntaxhighlight lang="cpp"> SpaceShip& theSpaceShipReference = theApolloSpacecraft; Asteroid& theAsteroidReference = theExplodingAsteroid; theSpaceShipReference.CollideWith(theAsteroid); theSpaceShipReference.CollideWith(theAsteroidReference); </syntaxhighlight> It prints out <code>Asteroid hit an ApolloSpacecraft</code> and <code>ExplodingAsteroid hit an ApolloSpacecraft</code>, as expected. The key is that <code>theSpaceShipReference.CollideWith(theAsteroidReference);</code> does the following at run time: # <code>theSpaceShipReference</code> is a reference, so C++ looks up the correct method in the vtable. In this case, it will call <code>ApolloSpacecraft::CollideWith(Asteroid&)</code>. # Within <code>ApolloSpacecraft::CollideWith(Asteroid&)</code>, <code>inAsteroid</code> is a reference, so <code>inAsteroid.CollideWith(*this)</code> will result in ''another vtable lookup''. In this case, <code>inAsteroid</code> is a reference to an <code>ExplodingAsteroid</code> so <code>ExplodingAsteroid::CollideWith(ApolloSpacecraft&)</code> will be called.
Edit summary
(Briefly describe your changes)
By publishing changes, you agree to the
Terms of Use
, and you irrevocably agree to release your contribution under the
CC BY-SA 4.0 License
and the
GFDL
. You agree that a hyperlink or URL is sufficient attribution under the Creative Commons license.
Cancel
Editing help
(opens in new window)