I have written - what seemed to be - exactly the same example of inheritance both in Java and C++. I am really amazed to see the different outputs of these programs. Let me share both code snippets and the corresponding outputs.
C++ Code:
class A
{
public:
A() {}
void sleep() {
cout << "A.Sleep" << endl;
eat();
}
void eat() {cout << "A.Eat" << endl;}
};
class B: public A
{
public:
B() {}
void sleep() {
A::sleep();
cout << "B.Sleep " <<endl;
this->eat();
}
void eat() {
cout << "B.Eat" << endl;
run();
}
void run() {
A::sleep();
cout << "B.run" << endl;
}
};
int main()
{
B *b = new B();
b->sleep();
}
Output:
A.Sleep
A.Eat
B.Sleep
B.Eat
A.Sleep
A.Eat
B.run
executed successfully...
Java Code:
class A
{
A() {}
void sleep() {
System.out.println("A.Sleep");
this.eat();
}
void eat() { System.out.println("A.Eat");}
};
class B extends A
{
B() {}
@Override
void sleep() {
super.sleep();
System.out.println("B.Sleep");
this.eat();
}
@Override
void eat() {
System.out.println("B.Eat");
run();
}
void run() {
super.sleep();
System.out.println("B.Run");
}
}
public class Test {
public static void main(String[] args) {
B b = new B();
b.sleep();
}
}
Output:
A.Sleep
B.Eat
A.Sleep
B.Eat
A.Sleep
......
......
......
(Exception in thread "main" java.lang.StackOverflowError)
I don't know why these two examples of inheritance behave differently. Shouldn't it work similarly?
What is the explanation for this scenario?
In your C++ example you are hiding the base methods, but you don't override them. So they are actually different methods which just happen to have the same name. If you are calling
A* a = new B();
a->sleep();
it will actually print "A.Sleep"
. If you want to override a method, you need to declare it virtual
in the Base class (automatically making it virtual in all sub classes too). You can read more about function hiding vs overriding in C++ in this post .
In your Java example you actually override the methods, so they are the same method. One taking the place of the old. You can think of it this way: all Java functions are secretly marked as virtual
, meaning they can be overridden. If you want a method to not be overridable in Java, you must declare it final
.
Note: be careful, every language as its own way of thinking . There is a lot of ways to interpret/implement OO. Even if C++ and Java looks similar, they are far from similar.
In both languages, the compiler verifies at compile-time if you can call a method, by examining the class (and the one inherited from the current one, etc) for a method of the right signature and visibility. What makes things different is the way the call is really emitted.
C++ :
In the case of non-virtual methods the method called is fully determined at compile-time . This is why even if the object is of class B
, when it is executing A::sleep
the call to eat
is resolved as a call to A::eat
( eat
is not virtual then compiler calls A::eat
because you are in level A
). In B::sleep()
the call to this->eat()
is resolved as a call to B.eat()
because at that place this
is of type B
. You can't go down to the inheritance hierarchy (call to eat
in class A
will never call an eat
method in a class below).
Be aware that things are different in the case of virtual methods (it is more similar to the Java case while being different).
Java :
In Java, the method called is determined at run-time , and is the one that is the most related to the object instance. So when in A.sleep
the call to eat
will be a call related to the type of the current object, that means of the type B
(because the current object is of type B
) then B.eat
will be called.
You then have a stack overflow because, as you are playing with an object of type B
a call to B.sleep()
will call A.sleep()
, which will call B.eat()
, which in turn will call B.run()
which will call A.sleep()
, etc in a never ending loop.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.