17

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.

aioobe
  • 413,195
  • 112
  • 811
  • 826
Kamel
  • 1,856
  • 1
  • 15
  • 25
  • I am sorry, but it is the last part of my comment. I really want to know how the type inference is implemented when calling `func2()` from `base::func1()`. – Kamel Jun 17 '15 at 12:46
  • Do you mean *How the `func2()` class binding being inferred?* – aioobe Jun 17 '15 at 12:47
  • Exactly. Which `fun2()` should be called and how it is determined. – Kamel Jun 17 '15 at 12:48
  • Expanded my answer. Please let me know if it's still unclear. – aioobe Jun 17 '15 at 12:57
  • Your expansion is great. But it would be more helpful if things behind `base::func1()` is explained. – Kamel Jun 17 '15 at 13:07
  • Made yet an attempt to explain. You're not super clear about what you find confusing. Asking me to explain "things behind `base::func1()`" sort of forces me to guess. – aioobe Jun 17 '15 at 13:16
  • No, the class itself is really not enough to infer `func2()` belong to `base` or `derive`. If `func2()` is *virtual*, then how to infer it belongs to which class? – Kamel Jun 17 '15 at 13:30
  • If it is virtual, it is the *runtime type* that determines which class it "belongs" to, i.e. the actual type of the object during execution. – aioobe Jun 17 '15 at 13:33
  • Previously, I thought all the function inferring is done though the casting `this` pointer, it seems `this` is only a pointer which stands for receiver object, it is used to find out the relative position of member field and function only. – Kamel Jun 17 '15 at 13:41

2 Answers2

24

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 as

virtual void func2(){
    printf(" I am in base:func2() \n");
}

In which case your program would have printed "I am in derived:func2()".

How the func2() class binding being inferred?
Which fun2() should be called and how it is determined.

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

Fruit f = new Banana();

the static type of f is Fruit and the runtime type of f is Banana.

If you do f.someNonVirtualMethod() the static type will be used and Fruit::someNonVirtualMethod will be called. If you do f.someVirtualMethod() the runtime type will be used and Banana::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 no, how this is able to reach to the function in base class?

void func1(){
    func2();
}

If you're wondering why func2() here calls base's func2 it is because

A) You're in the scope of base which means that the static type of this is base, and

B) func2 in base is not virtual, so it is the static type that decides which implementation to call.

Community
  • 1
  • 1
aioobe
  • 413,195
  • 112
  • 811
  • 826
  • 1
    (And conversely, making a method `final` does let you "opt out"...) – Louis Wasserman Jun 17 '15 at 06:44
  • 1
    @LouisWasserman Yes and no. It is the decision of the base class to not let the sub classes override a method when it is final. You even cannot declare a method with the same signature. As far as I understand, that is somewhat different to C++. – Seelenvirtuose Jun 17 '15 at 06:56
  • 1
    If a method can't be overridden it's meaningless to discuss whether it's virtual or not. I'd say private, final and static methods are neither virtual nor non-virtual because no one knows which method would be called if someone managed to override it. – aioobe Jun 17 '15 at 06:59
  • But how to understand the `base::func1()` ? Does it mean to change the `this` from `derived` type to `base` type? – Kamel Jun 17 '15 at 08:12
  • What happened when `base::func1()` is called? As it has something to do with the `func2()` in the base function. How the `func2()` class binding being inferred? – Kamel Jun 17 '15 at 08:20
  • This is typically implemented by having a method lookup table (a v-table). The base class overrides the entry in the table corresponding to `func2` so that `func2` is automatically called when invoking it on a `derived` object. Have a look at the Wikipedia article on [Virtual method table](https://en.wikipedia.org/wiki/Virtual_method_table). – aioobe Jun 17 '15 at 08:24
  • Well, if you have a `private` method, there *can* be a method with identical signature in the subclass which still doesn’t override the former. With package-private access, the picture might get really complicated… – Holger Jun 17 '15 at 11:59
  • Right. But as you say, it *doesn't* override it, so while it's kind of related, it still doesn't prove that private methods are non-virtual. – aioobe Jun 17 '15 at 12:01
  • Does it mean the behaviour of `base::func1()` is determined by the `class` it is in, but not inferred from the type of `this`? But `base` class really knows nothing of its `derive`! – Kamel Jun 17 '15 at 13:18
  • 1
    @aioobe: how do you define “non-virtual” then, if the absence of a virtual method call (actual runtime class based arbitration) does not suffice? – Holger Jun 17 '15 at 13:18
  • Wow, you got me :-) I'm now convinced it makes sense to say that private methods in Java are non-virtual. Thanks for hammering this into my head. – aioobe Jun 17 '15 at 13:34
0

In C++ you can only override a base class function if it is declared virtual. Since in your c++ example you haven't declared 'func2()' as virtual so it has not been overridden by derived class 'func2()`.

Whereas in Java you don't need to declare a function in the base class as virtual in order to override them.

Consider this Java example.

class Base{
  public void func2(){
    System.out.println("Base class func2()");
  }
}

class Derived extends Base{
  public void func2(){
    System.out.println("Derived class func2()");
  }
}

class Main extends Base{
  public static void main(String[] args) {
    Derived derived = new Derived();
    derived.func2();

    Base base = new Derived();
    base.func2();
  }
}

Output

Derived class func2()
Derived class func2()

If you want to declare a base class function as non-virtual in java, then declare that function as final. This will prevent the override of base class function in the derived class.

Example:

class Base{
  public final void func2(){
    System.out.println("Base class func2()");
  }
}

Some external links belong to my site.

Adarsh Kumar
  • 467
  • 6
  • 11
  • Based on the domain/URL of your link(s) being the same as, or containing, your user name, you appear to have linked to your own site/a site you're affiliated with. If you do, you *must disclose that it's your site*. If you don't disclose affiliation, it's considered spam. See: [**What signifies "Good" self promotion?**](//meta.stackexchange.com/q/182212) and [the help center on self-promotion](/help/promotion). Disclosure must be explicit, but doesn't need to be formal. When it's your own *personal* content, it can just be something like "on my site…", "on my blog…", etc. – Makyen Oct 06 '19 at 15:28