I wonder how dynamic dispatching really works in C++. To illustrate my question, I will start by some Java code.
class A
{
public void op(int x, double y) { System.out.println("a"); }
public void op(double x, double y) { System.out.println("b"); }
}
class B extends A
{
public void op(int x, double y) { System.out.println("c"); }
public void op(int x, int y) { System.out.println("d"); }
}
class C extends B
{
public void op(int x, int y) { System.out.println("e"); }
}
public class Pol
{
public static void main(String[] args)
{
A a = new C();
B b = new C();
/* 1 */ a.op(2, 4);
/* 2 */ b.op(2.0, 4.0);
}
}
The call a.op(2, 4)
will print "c", since indeed the compiler:
A
(since a
is declared to be a variable of type A
) which method is the closest to op(int, int)
,op(int, int)
method but finds the method op(int, double)
(with a single auto-cast int
-> double
),During the execution, the JVM:
op(int, double)
fixed by the compiler into Class C
but doesn't find it,B
,op(int, double)
, then calls it.The same principle applies to the call b.op(2.0, 4.0)
, which prints "b".
Now, consider the equivalent code in C++
#include <iostream>
class A
{
public:
virtual void op(int x, double y) { std::cout << "a" << std::endl; }
virtual void op(double x, double y) { std::cout << "b" << std::endl; }
};
class B : public A
{
public:
void op(int x, double y) { std::cout << "c" << std::endl; }
virtual void op(int x, int y) { std::cout << "d" << std::endl; }
};
class C : public B
{
public:
void op(int x, int y) { std::cout << "e" << std::endl; }
};
int main()
{
A *a = new C;
B *b = new C;
/* 1 */ a->op(2, 4);
/* 2 */ b->op(2.0, 4.0);
delete a;
delete b;
}
a->op(2, 4)
will print "c", like Java. But b->op(2.0, 4.0)
outputs "c" again, and there, I'm lost.
What are exactly the rules applied at the compilation and during the execution in C++ for dynamic dispatching?
(Notice you will have the same behavior from the C++ code if you write virtual
in front of each function; it changes nothing here)
Yes. It can be easily achieved. You would use an array of function pointers, then use those function pointers to make the call.
In computer science, dynamic dispatch is the process of selecting which implementation of a polymorphic operation (method or function) to call at run time. It is commonly employed in, and considered a prime characteristic of, object-oriented programming (OOP) languages and systems.
Dynamic dispatch, for example, is one of the features that make Objective-C as dynamic as it is. Dynamic what? Dynamic dispatch. It simply means that the Objective-C runtime decides at runtime which implementation of a particular method or function it needs to invoke.
Dynamic method dispatch is the mechanism in which a call to an overridden method is resolved at run time instead of compile time. This is an important concept because of how Java implements run-time polymorphism.
For C++, when you do b->op(2.0, 4.0);
the compiler looks in B
, finds a method it can call (int x, double y)
and uses it. It does not look in the superclass if any method in the subclass can handle the call. This is called method hiding, ie. op(double, double)
is hidden.
If you want to make it select the (double x, double y)
version, you need to make the function visible inside of B
with the following declaration inside B
:
using A::op;
Further explanation of the rules
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With