Dziedziczenie i interfejsy

0

Witam! Mam pytanie odnośnie interfejsów i dziedziczenia. Załóżmy, że mamy taka sytuację, że mamy 2 klasy, powiedzmy Car i Tiny, Tiny dziedziczy po Car, obie klasy implementują interfejs "IDriveable", który implementuje metodę "goForward()". Teraz tworze statyczną funkcję w tym samym pliku co funkcja główna "main", która jako argument pobiera argument typu "IDriveable", teraz jak przekazuję obiekt typu "Car" no to wykonuje się dla Car, natomiast jak podam typu Tiny to wykonuje się "goForward()" dla typu Tiny. Czyli polimorfizm dla interfejsu działa. Tylko teraz jak zdefiniuje funkcję, która jako argument przyjmuję typ "Car", i będę w niej wykonywał funkcje z interfejsu:

public static void checker(Car car)
{
     car.goForward();
} 

jak podam obiekt typu "Car", to wykona się dla typu Car, natomiast jak podaje obiekt typu "Tiny" ( który dziedziczy po Car, i implementuje ten sam interfejs) to polimorfizm już nie działa, i funkcja wykonuje się jak dla typu Car. No i teraz pytanie, czy w C# już tak po prostu jest? Dla typu Car nie uruchomię funkcji z interfejsu dla typu Tiny( tylko uruchomię oryginał)? I gdyby chciał żeby działało dla Tiny to bym musiał użyć słówka virtual i robić zwykły polimorfizm? Próbuję to jakoś zrozumieć..

1
public static void checker(IDriveable drivable)
{
     drivable.goForward();
} 

W C# masz kilka koncepcji:

virtual void metoda() {} // Tworzy NOWĄ metodę wirtualną z daną implementacją (jeszcze raz podkreślam nową, jeśli w klasie dziedziczącej napiszesz new virtual to dostaniesz drugą kopię i będzie to inna metoda wirtualna o tej samej nazwie)
override void metoda() {} // nadpisuje metodę wirtualną z klasy bazowej
abstract void metoda() {} // Tworzy metodę wirtualną bez podawania implementacji - tj. musisz ją nadpisać

//w interfejsie:
void metoda(); // dokładnie tak jak abstract, z minimum dwoma ważnymi wyjątkami - dla struktur nie koniecznie musisz dostać V-table jeśli nie używasz bezpośrednio interfejsu ORAZ możesz implementować więcej niż 1 interfejs w klasie

Jakkolwiek to nie zrobisz szablon wygląda zawsze tak samo:

KlasaBazowa o = new KlasaPochodna1();
// i operujesz na klasie/interfejsie bazowym, a nie na konkretnej implementacji interfejsu.
// jesli chcialbys sprawdzic czy dana implementacja interfejsu jest danej klasy:
bool jestKlasaPochodna1 = o is KlasaPochodna1;

// chcesz rzutowac, bez rzucania wyjatkiem w przypadku gdy sie nie da (dostaniesz null jesli nie jest):
KlasaPochodna1 p = o as KlasaPochodna1;

// chcesz rzutowac, ale jak sie nie uda to rzuc wyjatkiem:
KlasaPochodna1 p2 = (KlasaPochodna1)o;
0

no napisałem tak w pierwszej wersji, potem pytam o drugą wersję dlaczego tak nie może być skoro dziedziczy Tiny po Car i implementują ten sam interfejs.....Po prostu tak już jest w C# i żeby tego użyć muszę robić zwykły polimorfizm wtedy?

0

Wygląda to tak :
Klasa Car

 class Car : IDriveable
        {
            public void goUp() // z interfejsu
            {
                Console.WriteLine("Go with Car up");
            }
        }

        class Tiny : Car, IDriveable
        {
            public new void goUp() // z interfejsu
            {
                Console.WriteLine("Go with Tiny up");
            }
        }

        public interface IDriveable
        {
            void goUp();
        }

        //tam gdzie main
        public static void checker(Car id)
        {
            id.goUp();
        }


        public static void Main(string[] args)
        {
            Tiny tiny = new Tiny();
            checker(tiny);
        }

i moje pytanie dlaczego wykona się goUp dla Car, a nie dla Tiny ( skoro Tiny dziedziczy po Car i implementuje ten sam interfejs) czy tak jest po prostu w C# w związku z interfejsami? Bo wiem, że jesli argument w funkcji checker byłby IDriveable to wykonałoby się dla Tiny.

0

Zobacz co robi słówko "new" tutaj: public new void goUp().

1

To nie ma związku z interfejsami tylko z tym, że metoda Car.goUp nie jest wirtualna, więc niby jak mogłaby być wywołana jej wersja z klasy dziedziczącej?

0
somekind napisał(a):

metoda Car.goUp nie jest wirtualna, więc niby jak mogłaby być wywołana jej wersja z klasy dziedziczącej?

pewnie spaczenie z javy gdzie wszystkie metody są domyślnie wirtualne - swoją drogą mimo że nie lubię javy to wydaje mi się że to akurat bardziej przyjazne programiście podejście

@PolskaGola

Tiny nie musi już jawnie deklarować implementację IDriveable skoro już dziedziczy z Car który implementuje ten interfejs

0

no tylko ze jak nie dam w Tiny : IDriveable to nawet jak w checker est argument typu IDriveable i podam mu Tiny to wykonuje jako Car...(tzn dla klasy nadrzednej wykonuje goUp())

0

Zrób tą metodę goUp() w klasie Car jako virtual, w klasie Tiny daj jako override i wywal to niepotrzebne dziedziczenie po IDriveable i będzie działać tak jak chcesz żeby działało.

0

Ja wiem, że tak może działać po prostu pytałem czemu to nie działa razem z interfejsem i tyle.

0

To dziedziczenie po interfejsie w klasie Tiny akurat niczego nie zmienia.

http://stackoverflow.com/questions/159978/c-sharp-keyword-usage-virtualoverride-vs-new
2 odpowiedź, masz wyjaśnione.

//Ok, chyba chodziło Ci o co innego.
https://msdn.microsoft.com/en-us/library/aa664593%28v=vs.71%29.aspx

0

no właśnie jak mam funkcje checker i ona jako argument przyjmuje IDriveable. A ja w klasie Tiny dziedziczę po Car , która implementuje IDriveable, ale w samej Tiny nie implementuję IDriveable i potem w Tiny mam funkcje goUp(), to czemu jak podam obiekt typu Tiny do funkcji checker to wykona się goUp dla klasy nadrzednej od Tiny? To wtedy interfejs nie wie ze ja niby nadpisuje w Tiny funkcję goUp, bo jak dziedzicze po Car to w goUp nie ma virtual? Chodzi mi o taką sytuację:

 class Car : IDriveable
        {
            public void goUp() // z interfejsu
            {
                Console.WriteLine("Go with Car up");
            }
        }
 
        class Tiny : Car
        {
            public new void goUp() // z interfejsu
            {
                Console.WriteLine("Go with Tiny up");
            }
        }
 
        public interface IDriveable
        {
            void goUp();
        }
 
        //tam gdzie main
        public static void checker(Car id)
        {
            id.goUp();
        }
 
 
        public static void Main(string[] args)
        {
            Tiny tiny = new Tiny();
            checker(tiny);
        } 
2

Usuń wreszcie to new z definicji goUp w klasie Tiny.

0
somekind napisał(a):

Usuń wreszcie to new

to nic nie da, funkcja dalej będzie jedynie "przykrywać" zamiast przeciążać
new służy tylko do wyrażenia intencji że to celowe działanie i bez niego visual będzie podkreślał tę linię

@PolskaGola: nie wiem czego nie rozumiesz - tak działa język
jak podajesz obiekt do funkcji przyjmującej jakiś typ to obiekt ten przekazany zostaje jako instancja najwyższej możliwej implementacji tego typu

czyli jeżeli w Tiny jawnie zadeklarujesz że implementujesz IDriveable i przekazujesz do funkcji przyjmującej IDriveable to zostanie przekazana instancja Tiny, ale jeżeli dziedziczysz po Car i dopiero on implementuje IDriveable to instancja Tiny zostaje przekazana jako typ Car a więc zostaje wykonana jego metoda
żeby to zmienić oznacza się funkcje jako virtual lub abstract - wtedy program wykonując funkcję goUp w klasie nadrzędnej szuka "najgłębszej" implementacji która przeciąża tę funkcję (override) i ją odpala

inaczej mówiąc - z użyciem new w ogóle nie musisz dziedziczyć tutaj po Car bo Tiny jest całkowicie inną klasą z innymi (niepowiązanymi) metodami
zamiast new musisz użyć override a w klasie wyżej jak już wspominałem - abstract lub virtual

0
uuuuuu napisał(a):

to nic nie da, funkcja dalej będzie jedynie "przykrywać" zamiast przeciążać

Wiesz w ogóle co to jest przeciążanie metod? Wiesz, że w tym wątku w ogóle nie ma o tym mowy?

new służy tylko do wyrażenia intencji że to celowe działanie i bez niego visual będzie podkreślał tę linię

new służy do przerwania łańcucha polimorficznych wywołań, do ukrycia faktu, że metoda o tej samej sygnaturze jest zdefiniowana w klasie bazowej.
Usunięcie new da tyle, że w ogóle będziemy mogli zacząć rozmawiać o polimorfizmie, bo jeśli go na własne życzenie wyłączamy, to go po prostu nie ma.

0

Wiesz w ogóle co to jest przeciążanie metod? Wiesz, że w tym wątku w ogóle nie ma o tym mowy?

przepraszam, chodziło mi o przesłanianie - rzadko ogólnie korzystam z polskich terminów w programowaniu stąd pomyłka

1 użytkowników online, w tym zalogowanych: 0, gości: 1