2015-06-17 15 views
14

Dwie podobne definicje w języku Java i C++, ale zupełnie inne zachowanie. WersjaPrzesłanianie funkcji w języku 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(); 
    } 
} 

wyjściowa:

I am in derived:func2() 

C++ wersja:

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

wyjściowa:

I am in base:func2() 

Nie wiem, dlaczego mają inne zachowanie.

Nawet ja wiem, że Java ma zachowanie auto polimorfizmu.

Wyjście Java trudno zrozumieć osobiście.

Moim zdaniem według static scope funkcja klasy bazowej func1() powinien być w stanie wywołać funkcji klasy bazowej func2(), jak to w ogóle nic nie wie o klasie pochodnej tylko. W przeciwnym razie zachowanie wywołujące należy do dynamic scope. Może w C++, func2() w klasie bazowej jest powiązany static, ale w Javie jest to bind dynamic?

Pole członkowskie ma zakres statystyczny.


Część wnioskowania części jest myląca. Myślałem, że this jest konwertowane na base typu w base::func1(). W C++, base::func2() nie jest polimorfizmem, dlatego wywoływany jest base::func1(). Podczas gdy w języku Java, base::func2() jest polimorfizmem, tak nazwano devried::func2().

W jaki sposób wiąże się wiązanie klasy func2()? Lub Które fun2() powinno być wywoływane i jak jest określane.

Co się stało za base::func1()? Czy jest tu jakakolwiek obsada dla this (od derive do base)? Jeśli nie, w jaki sposób this jest w stanie osiągnąć funkcję w klasie base?

 void func1(){ 
      func2(); 
     } 

Useful discussion na coderanch.

+0

Przykro mi, ale to ostatnia część mojego komentarza. Naprawdę chcę wiedzieć, w jaki sposób implementacja typu jest zaimplementowana podczas wywoływania 'func2()' z 'base :: func1()'. – Kamel

+0

Masz na myśli * W jaki sposób można wywnioskować powiązanie klasy "func2()"? * – aioobe

+0

Dokładnie. Którego fun2() 'powinno się wywoływać i jak jest ono określane. – Kamel

Odpowiedz

21

W języku Java wszystkie metody, które można przesłonić, są automatycznie virtual. Nie ma mechanizmu wyboru (virtual) dla niego, tak jak jest w C++ (i nie ma sposobu, aby zrezygnować).

Java zachowuje się jak gdyby zadeklarował base::func2 jak

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

W takim przypadku program byłby wydrukowany "I am in derived:func2()".

W jaki sposób wiąże się wiązanie klasy func2()?
Którego fun2() należy wywołać i jak jest określane.

Do metod bez wirtualnego (metody C++ bez virtual modyfikator) jest to statyczny typu decyduje, który sposób połączenie. Statyczny typ zmiennej jest określany przez deklarację zmiennej i nie zależy od sposobu wykonania kodu.

przypadku metod wirtualnych (metodą C++ z virtual modyfikatora i wszystkich metod Java) Jest to rodzaj wykonawcze decyduje, który sposób połączenie. Typ środowiska wykonawczego to typ rzeczywistego obiektu w środowisku wykonawczym.

Przykład: Jeśli masz

Fruit f = new Banana(); 

statyczny typ f jest Fruit i rodzaj runtime f jest Banana.

Jeśli wykonasz f.someNonVirtualMethod(), użyty zostanie typ statyczny i zostanie wywołany Fruit::someNonVirtualMethod. Jeśli wykonasz f.someVirtualMethod(), zostanie użyty typ środowiska wykonawczego i zostanie wywołany Banana::someVirtualMethod.

Podstawowa implementacja sposobu, w jaki kompilator osiąga ten cel, zależy zasadniczo od implementacji, ale zazwyczaj używana jest tabela vtable. Szczegółowe informacje znajdują się


Jeśli nie, w jaki sposób this jest w stanie dotrzeć do funkcji w base klasie?

void func1(){ 
    func2(); 
} 

Jeśli zastanawiasz się, dlaczego func2() tutaj nazywa base „s func2 to dlatego

A) Jesteś w zakresie base co oznacza, że ​​statyczny typ this jest base, i

B) func2 w base jest nie wirtualny, więc to jest typ statyczny, który decyduje, który implementat ion zadzwonić.

+1

(I odwrotnie, zrobienie metody "final" pozwala ci "zrezygnować" ...) –

+1

@LouisWasserman Tak i nie. Decyzja klasy bazowej nie pozwala, aby podklasy przesłaniały metodę, gdy jest ona ostateczna. Nawet nie możesz zadeklarować metody z tym samym podpisem. O ile rozumiem, jest to trochę inaczej niż w C++. – Seelenvirtuose

+1

Jeśli nie można przesłonić metody, nie ma sensu omawiać, czy jest ona wirtualna czy nie. Powiedziałbym, że metody prywatne, końcowe i statyczne nie są ani wirtualne, ani wirtualne, ponieważ nikt nie wie, która metoda byłaby wywoływana, gdyby ktoś zdołał ją przesłonić. – aioobe