2015-06-17 20 views
14

Zwei ähnliche Definitionen in Java und C++, aber völlig anderes Verhalten.Funktion überschreiben in Java vs C++

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(); 
    } 
} 

Ausgang:

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; 
} 

Ausgang:

I am in base:func2() 

Ich weiß nicht, warum sie ein unterschiedliches Verhalten haben.

Selbst ich weiß, dass Java Auto-Polymorphie-Verhalten hat.

Die Java-Ausgabe ist persönlich schwer zu verstehen.

Meiner Ansicht nach static scope kann die Funktion der Basisklasse func1() sollte nur in der Lage, die Funktion der Basisklasse func2() zu nennen, wie es überhaupt nichts von der abgeleiteten Klasse kennt. Ansonsten gehört das aufrufende Verhalten zu dynamic scope. Vielleicht in C++, func2() in der Basisklasse ist bind static, aber in Java ist es bind dynamic?

Mitgliederfeld ist statisch begrenzt.


Der Typ Schlussfolgerung ist verwirrend. Ich dachte this wird in base Typ in umgewandelt. In C++ ist die base::func2() kein Polymorphismus, daher wird die genannt. Während in Java base::func2() Polymorphismus ist, wird devried::func2() genannt.

Wie wird die func2() Klassenbindung abgeleitet? Oder Welches fun2() sollte aufgerufen werden und wie es bestimmt wird.

Was ist hinter passiert? Gibt es hier eine Besetzung für this (von derive bis base)? Wenn nein, wie kann this die Funktion in base Klasse erreichen?

 void func1(){ 
      func2(); 
     } 

Useful discussion auf coderanch.

+0

Es tut mir leid, aber es ist der letzte Teil meines Kommentars. Ich möchte wirklich wissen, wie die Typinferenz implementiert wird, wenn 'func2()' von 'base :: func1()' aufgerufen wird. – Kamel

+0

Meinst du * Wie die 'func2()' Klassenbindung abgeleitet wird? * – aioobe

+0

Genau. Welches 'fun2()' aufgerufen werden soll und wie es bestimmt wird. – Kamel

Antwort

21

In Java sind alle Methoden, die überschrieben werden können, automatisch virtual. Es gibt keinen Opt-In-Mechanismus (virtual Schlüsselwort) für ihn, wie es in C++ ist (und es gibt auch keine Möglichkeit, sich abzumelden).

Java verhält sich, als ob Sie base::func2 als

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

In diesem Fall wird Ihr Programm erklärt hatte, haben "I am in derived:func2()" gedruckt würden.

Wie wird die func2() Klassenbindung abgeleitet?
Welches fun2() sollte aufgerufen werden und wie es ermittelt wird.

Für nicht-virtuelle Methoden (C++ Methoden ohne Modifikator virtual) es ist der statische Typ die zu nennen, welche Methode bestimmt. Der statische Typ der Variablen wird durch die Variablendeklaration bestimmt und hängt nicht davon ab, wie der Code ausgeführt wird.

Für virtuelle Methoden (C++ Methoden mit dem Modifikator virtual und alle Java-Methoden), ist es der Laufzeittyp die zu nennen, welche Methode bestimmt. Der Laufzeittyp ist der Typ des tatsächlichen Objekts in Runtime.

Beispiel: Wenn Sie

Fruit f = new Banana(); 

der statische Typ von f haben, ist Fruit und der Laufzeittyp von f ist Banana. Wenn Sie f.someNonVirtualMethod() tun, wird der statische Typ verwendet und Fruit::someNonVirtualMethod wird aufgerufen. Wenn Sie f.someVirtualMethod() tun, wird der Laufzeittyp verwendet und Banana::someVirtualMethod wird aufgerufen.

Die zugrunde liegende Implementierung, wie der Compiler dies erreicht, ist im Wesentlichen implementierungsabhängig, aber normalerweise wird eine vtable verwendet. Details siehe


Wenn nein, wie this auf die Funktion in base Klasse zu erreichen ist in der Lage?

void func1(){ 
    func2(); 
} 

Wenn Sie sich fragen, warum func2() hier nennt base ‚s func2 es ist, weil

A) Sie sind im Rahmen der base was bedeutet, dass der statische Typ von thisbase ist, und

B) func2 in base ist nicht virtuell, so ist es der statische Typ, was Realisierun entscheidet zu rufendes Ion.

+1

(Und umgekehrt, lassen Sie eine Methode 'final' lassen Sie" Opt-out "...) –

+1

@LouisWasserman Ja und Nein. Es ist die Entscheidung der Basisklasse, dass die Unterklassen eine Methode nicht überschreiben dürfen, wenn sie endgültig ist. Sie können sogar keine Methode mit der gleichen Signatur deklarieren. Soweit ich weiß, ist das etwas anders als in C++. – Seelenvirtuose

+1

Wenn eine Methode nicht überschrieben werden kann, ist es sinnlos zu diskutieren, ob sie virtuell ist oder nicht. Ich würde sagen, dass private, finale und statische Methoden weder virtuell noch nicht virtuell sind, weil niemand weiß, welche Methode aufgerufen würde, wenn jemand sie überschreiben könnte. – aioobe