Two similar definitions in Java and C++, but totally different behaviour.
Java version:
class base{
public void func1(){
func2();
}
public void func2(){
System.out.println(" I am in base:func2() \n");
}
}
class derived extends base{
public void func1(){
super.func1();
}
public void func2(){
System.out.println(" I am in derived:func2() \n");
}
};
public class Test
{
public static void main(String[] args){
derived d = new derived();
d.func1();
}
}
output:
I am in derived:func2()
C++ version:
#include <stdio.h>
class base
{
public:
void func1(){
func2();
}
void func2(){
printf(" I am in base:func2() \n");
}
};
class derived : public base
{
public:
void func1(){
base::func1();
}
void func2(){
printf(" I am in derived:func2() \n");
}
};
int main()
{
derived *d = new derived();
d->func1();
return 0;
}
output:
I am in base:func2()
I don't know why they have different behaviour.
Even I know Java has auto polymorphism behaviour.
The Java output is hard to understand personally.
In my view, according to static scope
, the base class function func1()
should only be able to call the base class function func2()
, as it knows nothing about the derived class at all. Otherwise the calling behaviour belongs to dynamic scope
.
Maybe in C++, func2()
in base class is bind static
, but in Java it is bind dynamic
?
Member field is statically scoped.
The type inferring part is confusing.
I thought this
is converted to base
type in the base::func1()
. In C++, the base::func2()
is not polymorphism, so the base::func1()
is called.
While in Java, base::func2()
is polymorphism, so devried::func2()
is called.
How the func2()
class binding being inferred? Or
Which fun2()
should be called and how it is determined.
What happened behind base::func1()
? Is there any cast here for this
(from derive
to base
)?
If no, how this
is able to reach to the function in base
class?
void func1(){
func2();
}
Useful discussion on coderanch.
In Java all methods that can be overridden are automatically virtual. There is no opt-in mechanism (
virtual
keyword) for it as it is in C++ (and there's no way to opt-out either).Java behaves as if you had declared
base::func2
asIn which case your program would have printed
"I am in derived:func2()"
.For non-virtual methods (C++ methods without
virtual
modifier) it is the static type that determines which method to call. The static type of the variable is determined by the variable declaration and does not depend on how the code is executed.For virtual methods (C++ methods with the
virtual
modifier and all Java methods) it is the runtime type that determines which method to call. The runtime type is the type of the actual object in runtime.Example: If you have
the static type of
f
isFruit
and the runtime type off
isBanana
.If you do
f.someNonVirtualMethod()
the static type will be used andFruit::someNonVirtualMethod
will be called. If you dof.someVirtualMethod()
the runtime type will be used andBanana::someVirtualMethod
will be called.The underlying implementation for how the compiler achieves this is basically implementation dependent, but typically a vtable is used. For details refer to
If you're wondering why
func2()
here callsbase
'sfunc2
it is becauseA) You're in the scope of
base
which means that the static type ofthis
isbase
, andB)
func2
inbase
is not virtual, so it is the static type that decides which implementation to call.