2015-06-17 21 views
14

Due definizioni simili in Java e C++, ma un comportamento completamente diverso. VersioneOverride delle funzioni in Java vs C++

Java:

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

uscita:

I am in derived:func2() 

C++ versione:

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

uscita:

I am in base:func2() 

Non so perché hanno un comportamento diverso.

Anche io so che Java ha un comportamento auto polimorfismo.

L'output Java è difficile da comprendere personalmente.

A mio avviso, in base alla static scope, la funzione di classe di base func1() dovrebbe essere solo in grado di chiamare la funzione della classe base func2(), in quanto non sa nulla della classe derivata a tutti. In caso contrario, il comportamento di chiamata appartiene a dynamic scope. Forse in C++, func2() nella classe base è bind static, ma in Java è dynamic vincolante?

Il campo membro è a livello di ambito.


Il tipo inferenza parte è confusa. Ho pensato che il this sia stato convertito nel tipo base nello base::func1(). In C++, il base::func2() non è polimorfismo, quindi viene chiamato il base::func1(). Mentre in Java, base::func2() è il polimorfismo, viene chiamato devried::func2().

Come viene dedotta la legatura della classe func2()? O Quale fun2() dovrebbe essere chiamato e come viene determinato.

Che cosa è successo dopo base::func1()? C'è un getto qui per this (da derive a base)? Se no, come this è in grado di raggiungere la funzione nella classe base?

 void func1(){ 
      func2(); 
     } 

Useful discussion su coderanch.

+0

Mi dispiace, ma è l'ultima parte del mio commento. Voglio davvero sapere come viene implementata l'inferenza di tipo quando si chiama 'func2()' da 'base :: func1()'. – Kamel

+0

Intendi * Come viene inferta l'associazione di classe 'func2()'? * – aioobe

+0

Esatto. Quale 'fun2()' dovrebbe essere chiamato e come viene determinato. – Kamel

risposta

21

In Java tutti i metodi che possono essere ignorati sono automaticamente virtual. Non esiste un meccanismo di attivazione (parola chiave virtual) come in C++ (e non è possibile neanche optare per l'eliminazione).

Java si comporta come se si fosse dichiarato base::func2 come

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

In questo caso il programma avrebbe stampato "I am in derived:func2()".

Come viene dedotta la legatura della classe func2()?
Quale fun2() deve essere chiamato e come viene determinato.

Per i metodi non virtuali (C++ metodi senza virtual modificatore) è del tipo statico che determina quale metodo da chiamare. Il tipo statico della variabile è determinato dalla dichiarazione della variabile e non dipende da come viene eseguito il codice.

Per metodi virtuali (C++ metodi con il modificatore virtual e tutti metodi Java) è il tipo runtime che determina quale metodo da chiamare. Il tipo di runtime è il tipo dell'oggetto reale in runtime.

Esempio: Se avete

Fruit f = new Banana(); 

il tipo statico di f è Fruit e il tipo di esecuzione di f è Banana.

Se si utilizza f.someNonVirtualMethod(), verrà utilizzato il tipo statico e verrà chiamato Fruit::someNonVirtualMethod. Se si esegue f.someVirtualMethod(), verrà utilizzato il tipo di runtime e verrà chiamato il numero Banana::someVirtualMethod.

L'implementazione sottostante per il modo in cui il compilatore raggiunge questo è sostanzialmente dipendente dall'implementazione, ma in genere viene utilizzato un vtable. Per i dettagli fare riferimento al


Se no, come this è in grado di raggiungere la funzione nella base classe?

void func1(){ 
    func2(); 
} 

Se vi state chiedendo perché func2() qui chiama base s' func2 è perché

A) Siete nel campo di applicazione del base che significa che il tipo statico di this è base, e

B) func2 in base è non virtuale, quindi è il tipo statico che decide che implementat ione da chiamare.

+1

(E al contrario, rendere un metodo 'final' ti consente di" disattivare "...) –

+1

@LouisWasserman Sì e no. È la decisione della classe base di non lasciare che le sottoclassi sostituiscano un metodo quando è definitivo. Non puoi nemmeno dichiarare un metodo con la stessa firma. Per quanto ho capito, è un po 'diverso dal C++. – Seelenvirtuose

+1

Se un metodo non può essere sovrascritto, non ha senso discutere se sia virtuale o meno. Direi che i metodi privati, finali e statici non sono né virtuali né non virtuali perché nessuno sa quale metodo sarebbe chiamato se qualcuno fosse riuscito a sovrascriverlo. – aioobe

Problemi correlati