• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Polimorfizm java vs c++

Object Storage Arubacloud
0 głosów
1,112 wizyt
pytanie zadane 31 lipca 2016 w Java przez itcloud Gaduła (3,380 p.)

Uczę się jednocześnie Javy i c++ i trochę mi się zaczęło mieszać przy polimorfizmie.

Filmik1 (java) https://www.youtube.com/watch?v=gfQjtVZ35bM

Filmik2 (c++, Mirosław Zelent) https://www.youtube.com/watch?v=9hGPe6BnTY4

## JAVA

W pierwszym filmiku - w przypadku javy - prezentujący tłumaczy, że polimorfizm można zauważyć przy tablicy, która ma przechowywać obiekty (enkapsulacja pewnego rodzaju?) różnych typów. Warunek jest taki, że te obiekty muszą pochodzić z klas, które rozszerzają klasę bazową (słówko extends, dziedziczenie). I gdy chce wywołać dla danego obiektu metodę (która jest w każdej z klas dziedziczących, jak i w tej bazowej), to java wie doskonale, że jak ma do czynienia z obiektem A, to ma wywołać jego metodę (która defacto przysłania tę metodę z klasy bazowej). Ale zastanawia mnie, czemu tutaj nie ma żadnych metod/klas wirtualnych, abstrakcji jak przy interfejsie. Nawet można korzystać z metod które są w tej klasie bazowej. Ok - tu mi się być może myli z interfejsami (abstract) ? Czy to zatem wyczerpuje przykład polimorfizmu w javie? Ktoś może podać inny przykład?

## C++

Tutaj Mirosław Zelent łączy polimorfizm z funkcjami wirtualnymi (więc już nie wiem sam, czy polimorfizm bez tych funkcji wirtualnych to nadal polimorfizm, czy już przechodzimy do interfejsów / w javie tzw. abstrakcji??). Mowa jest też o wskaźniku, że jeśli wywołuje podobnie jak w javie jakąś metodę na rzecz obiektu, który dziedziczy z klasy podstawowej, to ten magiczny wskaźnik pokazuje na właściwą metodę (nie tą z klasy bazowej) ? O co chodzi z tym wskaźnikiem?

Najlepiej jakby mi to ktoś wytłumaczył w odniesieniu do obu języków. Z góry dziękuję.

 

3 odpowiedzi

+1 głos
odpowiedź 31 lipca 2016 przez Szykem2 Nałogowiec (29,510 p.)
edycja 31 lipca 2016 przez Szykem2

W Javie wszystkie metody niestatyczne, niefinalne i nieprywatne są wirtualne, ale JVM jest dość sprytna i się może domyśleć, że istnieje tylko jedna implementacja metody i użyć wczesnego wiązania.

JAVA:

public class Animal {
    private String name;

    public Animal(String name){
        this.name = name;
    }

    public void walk(int distance) {
        System.out.println(name + " idzie " + distance);
    }
}

public class Dog extends Animal {

    public Dog(String name) {
        super(name);
    }

    @Override
    public void walk(int distance) {
        System.out.printon("Pies " + name + " idzie " + distance);
    }
}

public class main {
    public static void main(String[] args) {
        Animal an = new Animal("cos");
        an.walk(10);                                //cos idzie 10
        Animal d = new Dog("doggy");
        d.walk(10):                                  //Pies doggy idzie 10
    }
}

Jak widzisz przy polimorfiźmie w Javie występuje przed nazwą metody @Override sugerujące, że jest to wersja metody odziedziczonej.

W Javie wszystkie obiekty dziedziczą z klasy Object, dzięki czemu łatwo jest zrobić niektóre rzeczy(jak np. wypisywanie wystarczy utworzyć metodę public String toString(), a nie przeładowywać operator << jak w C++ co dla początkujących bywa dość trudne).

Interfejs w Javie jest porównywalna do deklaracji klasy w C++, z tym, że nie może mieć swojej własnej implementacji(nie licząc metod domyślnych), musi mieć klasy implementujące. Klasa abstrakcyjna musi mieć implementację metod, chyba że też są abstrakcyjne.

C++ (ten sam przykład):

class Animal {
    string name;

    public:
    Animal(std::string name){
        this->name = name;
    }

    virtual void walk(int distance) {
        std::cout << name + std::string(" idzie ") + std::to_string(distance) << std::endl;
    }
}

class Dog : public Animal {

    public: 
    Dog(std::string name) : Animal(name) {}

    void walk(int distance) {
        std::cout << std::string("Pies ") + name + std::string(" idzie ") + std::to_string(distance) << std::endl;
    }
}

int main(int argc, char** argv)
{
        Animal* an = new Animal("cos");
        an->walk(10);                                //cos idzie 10
        Animal* d = new Dog("doggy");
        d->walk(10):                                  //Pies doggy idzie 10
}

W C++ musisz jawnie zadeklarować, że metoda jest wirtualna, żeby kompilator przygotował odpowiednią tablicę vtable. Musisz jawnie sprecyzować po to, aby program był wydajniejszy. Jeśliby każda metoda była wirtualna jak w Javie to C++ byłby znacznie mniej wydajny przez co miałby mniej zastosowań.

W C++ operator new zwraca wskaźnik, a nie jak w Javie referencję, więc musisz nieco inaczej obsługiwać takie obiekty(właśnie używając operatora ->).

komentarz 31 lipca 2016 przez Ehlert Ekspert (212,670 p.)
To co napisałeś jest nieprawdą. Nie poruszyłeś kwestii polimorfizmu. To jest po prostu zwykłe dziedziczenie z nadpisaniem jednej funkcji.
komentarz 31 lipca 2016 przez Szykem2 Nałogowiec (29,510 p.)
Możesz sprecyzować co dokładnie jest według Ciebie nieprawdą?
komentarz 31 lipca 2016 przez Ehlert Ekspert (212,670 p.)

Jak widzisz przy polimorfiźmie w Javie występuje przed nazwą metody @Override sugerujące, że jest to wersja metody odziedziczonej.

To jest aspekt dotyczący po prostu dziedziczenia. 

komentarz 31 lipca 2016 przez Szykem2 Nałogowiec (29,510 p.)

Nawet jeśli, to nie jest to kłamsto. Jeśli coś jest prawdą tylko nie na temat to nie obrażaj ludzi nazywając ich kłamcami. Jeżeli nie byłoby @Override to byłoby przesłanianie metody, a z @Override jest używane przy polimorfiźmie. LINK

1
komentarz 31 lipca 2016 przez Ehlert Ekspert (212,670 p.)
  1. Nie nazwałem Cię kłamcą. Nie obraziłem Cię.
  2. @Override jest związane z polimorfizmem ponieważ sam polimorfizm bazuje na dziedziczeniu.

 

komentarz 31 lipca 2016 przez itcloud Gaduła (3,380 p.)

Nie kłócić się. Ok, ale to jest ten przykład polimorfizmu?

Bo:

       Dog d = new Dog("doggy");
        d.walk(10): 

Tutaj podajesz przy tworzeniu obiektu typ klasy, która jest podklasą (dziedziczy), więc w tym przykładzie wiadomo, która metoda będzie wywołana (walk z klasy Dog).

komentarz 31 lipca 2016 przez Szykem2 Nałogowiec (29,510 p.)
1. Nie martw się nie czuję się obrażony, ale mimo wszystko sugeruję pisać nieco łagodniej bo znam ludzi co się mogą naprawdę obrazić.

2. Skoro to napisałeś to proszę wytłumacz mi dokładnie gdzie w tym zdaniu, które zacytowałeś jest błąd logiczny/merytoryczny.
komentarz 31 lipca 2016 przez Ehlert Ekspert (212,670 p.)

To nie to xD

Gdyby d byłoby typu Animal to byłby to polimorfizm.

1
komentarz 31 lipca 2016 przez Szykem2 Nałogowiec (29,510 p.)
No to dochodzimy do porozumienia. Dzięki poprawione :). Głupi błąd zmęczonego człowieka.
+1 głos
odpowiedź 31 lipca 2016 przez Ehlert Ekspert (212,670 p.)
edycja 31 lipca 2016 przez Ehlert

Napisałem Ci przykład z C++. W Javie wygląda to dokładnie tak samo, przy czym jeszcze lepiej ponieważ masz interfejsy, klasy czysto abstrakcyjne itp.
 

#include <iostream>
#include <string>

class Weapon;

class Hero
{
private:
    std::string name;
public:
    Hero(std::string name)
    :
    name    (name)
    {}
    
    ~Hero(){}
    
    void sayName(){
        std::cout << name << "\n";
    }
    
    virtual void attack() = 0;
    virtual void specialSkill() = 0;
};

class Warrior : public Hero
{
private:
    Weapon axe;
public:
    Warrior(std::string name = "Jack")
    :Hero(name)
    {}
    
    ~Warrior(){}
    
    void attack(){
        axe.use();
    }
    
    void specialSkill(){
        axe.putUp();
        axe.superCut();
    }            
};

class Monk : public Hero
{
private:
    Weapon stick;
    
    void jump(){
        //......
    }

public:
    Monk(std::string name = "Jack")
    :Hero(name)
    {}
    
    ~Monk(){}
    
    void attack(){
        stick.hit();
    }
    
    void specialSkill(){
        stick.doubleHit();
        jump();
        stick.hit();
    } 
    
};

int main()
{
    Hero * heroOperator;
    //Którą chcesz mieć postać...
    //......
    {
    case '1':
        heroOperator = new Warrior(name);
        break;
    case '2':
        heroOperator = new Monk(name);
        break;
    }
    
    std::cout << "Let's go! ";
    heroOperator->sayName();
    heroOperator->specialSkill();
}

Kod nie jest do skompilowania bo masz obiecanie typu Weapon i kilka innych wycięć. Chodzi o to, zebyś zrozumiał samą ideę.

Tworzę sobie wskaźnik polimorficzny o nazwie HeroOperator. Jest typu Hero więc może wskazywać na obiekty dziedziczące po tej klasie. Jak widzisz każda klasa na swój sposób nadpisała wirtualne metody. Teraz możesz za pośrednictwem tego wskaźnika wykorzystywać w pełni funkcjonalność i klasy Monk, i klasy Warrior.

PS. W mainie masz wyrwany z kontekstu switch. W Javie nie możesz używać switcha dla typu String. smiley

komentarz 31 lipca 2016 przez itcloud Gaduła (3,380 p.)
Po krótce to rozumiem, większość czaję: tzn. jest to podobnie jak w javie wyrażenie na początku samym, przy konstruowaniu klas i metod, że te klasy które dziedziczą, tak jakby nadpisują metody tej klasy wirtualnej i dlatego możemy utworzyć tylko jeden raz w kodzie wskaźnik na dany obiekt (ten z klasy bazowej) i po znaku równości przypisywać go (kazać mu, żeby odtąd wskazywał...) do jednego z tych obiektów, który dziedziczy z klasy bazowej?

Nie bardzo jeszcze rozumiem tego zastosowania, co to nam ułatwia :)

...ale jednak chyba skupię się na javie, aby potem powrócić do c++ bo naprawdę mi się to miesza. Poza tym tak na co dzień definiujesz stringa w c++? std::string ? Czyli rozumiem że string to jakaś klasa wbudowana w c++ i bez using namespace std trzeba cały czas się do tej STD odwoływać ?
komentarz 31 lipca 2016 przez Ehlert Ekspert (212,670 p.)

Dobrze zrozumiałeś. Polimorfizm będzie ułatwieniem przy większych projektach pisanych całkowicie obiektowo z wykorzystaniem wzorców projektowych.

Typ string w C++ ma bibliotekę którą trzeba dołączyć. Bez using.... musisz cały czas używać std.

0 głosów
odpowiedź 1 sierpnia 2016 przez itcloud Gaduła (3,380 p.)
Z tego co poczytałem jeszcze o polimorfizmie to wynika, że np. w JAVA to po prostu nic innego jak dziedziczenie, przesłanianie metod z tej klasy abstrakcyjnej przez metody o takich samych nazwach w klasach rozszerzających (tych które dziedziczą z tej klasy abstrakcyjnej). W związku z tym mam jeszcze krótkie pytania:

1. Zwierze kotek = new Kot();   - tutaj powstaje obiekt (egzemplarz klasy Zwierze czy egzemplarz klasy Kot ?)

2. Do tego wyżej - rozumiem, że motoda w klasie Kot np. daj_glos() przesłania metodę daj_glos w klasie Zwierze - i czy tamta klasa bazowa musi być abstrakcyjna? Kiedy natomiast sama metoda mogłaby być abstrakcyjna? Ja rozumiem, że w bazowej klasie raczej cała ta klasa powinna być abstrakcyjna, bo i tak większość (no właśnie - nie wszystkie muszą!) metod jest przesłaniana. Może to ktoś mi wytłumaczyć łopatologicznie?

3. W innym wątku wczoraj jeden z kolegów napisał, że w C++ mogę utworzyć egzemplarz klasy pod zmienną wskaźnikową i będzie on zapisany na stercie. Czyli:

MojaKlasa *wsk = new MojaKlasa();

a) Rozumiem, że zapis bez wksaźnika dla wsk nie miałby sensu? Ew. dlaczego ? :)

b) Podano też sposób utworzenia egzemplarza klasy, ale na STOSIE:

Typ zmienna;

Tutaj na stosie jest tworzony również egzemplarz klasy? To wyżej z ppkt a) różni się tylko tym, że jest alokowana pamięć dla obiektu klasy MojaKlasa i wywoływany konstruktora MojaKlasa() no i zwracany adres pod którym te dane będą dostępne (w zmiennej wskaźnikowej wsk), a w przykładzie b) powstaje po prostu zmienna JESZCZE BEZ OBIEKTU???

c) to co podano w b) zauważyłem że nie ma miejsca w Javie ???
1
komentarz 2 sierpnia 2016 przez Szykem2 Nałogowiec (29,510 p.)
„ przesłanianie metod z tej klasy abstrakcyjnej przez metody o takich samych nazwach” - nie nazwach a sygnaturach

void fun(int a) <- sygnatura

fun <- nazwa

jeżeli mają takie same nazwy to może to być tylko przeładowanie(różnią się ilością argumentów lub ich typem)

void fun(int a, int b) – funkcja przeładowana do funkcji void fun(int a)

1. Zwierze kotek = new Kot(); - kod w Javie. Kotek to referencja do typu Zwierze operatorem new tworzysz obiekt typu Kot, który jest rozszerzeniem typu zwierze, czyli de facto jest typu Zwierzę(dzięki dziedziczeniu można przypisać referencji typu nadrzędnego obiekt typu podrzędnego, a nie na odwrót: Rower jest typem pojazdu, ale pojazd nie jest typem roweru)

2. Klasa bazowa nie musi być abstrakcyjna, aczkolwiek powinno się robić tak, aby coś czego nie powinno się móc utworzyć w rzeczywistym świecie, było abstrakcyjne. (Pojazdu nie możesz utworzyć bo nie wiesz jak: ile kół, mechaniczny elektryczny czy spalinowy). Klasa abstrakcyjna nie musi mieć abstrakcyjnych metod(możesz po prostu nie potrzebować innych wersji w klasach dziedziczących, wtedy używasz tych z klasy bazowej). Metod abstrakcyjnych używasz tylko jeśli chcesz podać jaki jest interfejs klasy(choć nie ma sensu w javie robić klasy abstrakcyjnej z wszystkimi abstrakcyjnymi metodami lepiej wtedy użyć interfejsu)

3. W C++ operator new, w przeciwieństwie do Jaby, zwraca wskaźnik więc bez tej gwiazdki byłby błąd kompilacji(niezgodność typów). Operator new tworzy obiekty na stercie, a np.

Kot kitty; tworzy obiekt kitty typu Kot na stosie. W Javie nie masz bezpośrednio dostępu do obiektów, wszystko jest przez referencje, w C++ kitty(z przykładu) jest obiektem, w Javie byłby rzucony NullPointerException przy próbie modyfikacji obiektu,a w C++ masz obiekt i robisz co chcesz(w sensie co możesz zrobić). W Javie wszystko poza typami podstawowymi musi być utworzone operatorem new, więc to wszystko ląduje na stercie.
komentarz 2 sierpnia 2016 przez itcloud Gaduła (3,380 p.)
Dzięki.

Podobne pytania

0 głosów
1 odpowiedź 448 wizyt
pytanie zadane 16 października 2018 w Java przez Kubs Mądrala (5,190 p.)
0 głosów
1 odpowiedź 581 wizyt
pytanie zadane 25 czerwca 2018 w C i C++ przez niezalogowany
0 głosów
1 odpowiedź 162 wizyt
pytanie zadane 8 czerwca 2018 w C i C++ przez Fretkamaciejek Nowicjusz (190 p.)

92,545 zapytań

141,387 odpowiedzi

319,503 komentarzy

61,930 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...