dziwny sposób tworzenia obiektów

0

Cześć : )

Proszę o cierpliwość i wyrozumiałość. C# uczę się drugi tydzień. Korzystam z kursów online, filmików, tutoriali zaś podstawowym źródłem mojej wiedzy są pozycje: C# w pigułce oraz C# Rusz Głową. Dopiero zaczynam.

Mam duży problem w temacie polimorfizmu. Problem rozbija się przede wszystkim o tworzenie instancji nowej klasy.

class BaseClass  
{  
    public void Method1()  
    {  
        Console.WriteLine("Base - Method1");  
    }  
}  

class DerivedClass : BaseClass  
{  
    public void Method2()  
    {  
        Console.WriteLine("Derived - Method2");  
    }  
}

Teraz przechodzę do tworzenia instancji tych klas.

class Program  
{  
    static void Main(string[] args)  
    {  
        BaseClass bc = new BaseClass();  
        DerivedClass dc = new DerivedClass();  
        BaseClass bcdc = new DerivedClass();  

        bc.Method1();  
        dc.Method1();  
        dc.Method2();  
        bcdc.Method1();  
    }  
    // Output:  
    // Base - Method1  
    // Base - Method1  
    // Derived - Method2  
    // Base - Method1  
}

Moje pytanie są następujące:
Jaki jest sens tego zapisu:

        BaseClass bcdc = new DerivedClass();  

Tworzę obiekt w klasie DerivedClass jednak jego referencja będzie pochodzić z klasy bazowej BaseClass ? Jeśli tak, to po co mam tak robić? Nie mógłbym od razu stworzyć obiektu i jego referencji w tej samej klasie?

Z góry dziękuję za odpowiedź.

1

Ma to sens jeżeli korzystasz z metod wirtualnych.

1

Dla pojedynczego przypadku to może i nie ma sensu (albo ma tak jak napisał @Azarien) ale gdybyś miał nadrzędną klasę Car i chciał mieć kontener samochodów różnych marek, takich jak Volvo, Peugeot i sto innych to przecież nie będziesz tworzyć osobnych kontenerów dla poszczególnych marek tylko robisz List<Car> i masz w środku od razu Peugeoty i co tam chcesz.

Robisz powiedzmy:

var cars = new List<Car>();
cars.Add(new Peugeot());
cars.Add(new Volvo());

I to działa, bo choć wsadzasz różne typy to jednak wszystkie są samochodami.

PS:
Dla ścisłego wytłumaczenia, bo widzę, że ciężko idzie:

  • Car to BaseClass
  • Peugeot to DerivedClass
0

@Azarien, nic nie rozumiem. Mógłbyś rozwinąć swoją wypowiedź?

@grzesiek51114 co ma Twoja odpowiedź wspólnego z mim pytaniem?

0
class BaseClass
{
    public virtual void Foo()
    {
        System.Console.WriteLine("Base - Foo");
    }
}

class DerivedClass : BaseClass
{
    public override void Foo()
    {
        System.Console.WriteLine("Derived - Foo");
    }
}

class Program
{
    static void CallFoo(BaseClass obj)
    {
        obj.Foo();
    }

    static void Main(string[] args)
    {
        BaseClass bc1 = new BaseClass();
        BaseClass bc2 = new DerivedClass();

        CallFoo(bc1);
        CallFoo(bc2); // magic!
    }
}
0

@Azarien : Wydaje mi się, że CallFoo(bc1) napisze Base-Foo. Popraw mnie jeśli się mylę. bc1 jest obiektem typu BaseClass, którego referencja również jest w tej klasie. Zatem wywołując metodę Foo , bc1 "sięgnie po nią" do swojej klasy BaseClass. Natmiast CallFoo(bc2) wywoła napis: Derived-Foo. bc2 jest oniektem typu DerivedClass ale jego referencja "sięga po metody" do BaseClass. Ale w BaseClass metoda Foo jest wirtualna i zostanie ona przesłonieta przez metodę Foo z z DerivedClass. Czy wszystko powiedziałem poprawnie?

0

w Twoim przykładzie już to rozumiem. Niemniej czy przez to, że tak dodajesz te nowe samochody nie zabierasz im trochę właściwości? Z tego co tutaj widzę, to jest to niejawne rzutowanie w górę. I czy przypadkiem przez to nie mamy teraz tylko referencji do metod i pól w klasie Car? A co jeśli klasa Peugeot, klasa Volvo miały coś w sobie?

Jak widać nie ma z tym żadnego problemu. Własności również mogą być wirtualne:

using System;

namespace App
{
    abstract class Base
    {
        public virtual string Name
        {
            get => "Base";
        }
    }

    class Derived : Base
    {
        public override string Name
        {
            get => "Derived";
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Base obj = new Derived();
            Console.WriteLine(obj.Name);
        }
    }
}

obj doskonale "wie" jakiej klasy jest obiektem i nie musisz martwić się tutaj rzutowaniem. Wszystko załatwia wirtualność. Gdyby w Derived była własność, której nie ma w Base to oczywiście nie miałbyś do niej dostępu za pomocą sposobu, który przedstawiłem wyżej. Wszystko trzeba projektować z głową :)

0

@grzesiek51114: Twój przykład rozumiem. Jednak nadal - czy pisanie tutaj

            Base obj = new Derived();

nie jest dziwne? Czy nie lepiej byłoby napisać:

            Derived obj = new Derived();

i mieć "w razie co" dostęp do wszystkiego co ma podklasa Derived? Nie wiem, czy my się rozumiemy. Dla mnie, tak an chłopski rozum, rzutowanie w górę to tracenie dostępu, zawężanie sobie możliwości a przede wszystkim komplikowanie. Obiekt jest tworzony w jednej klasie, a referencja do niego jest gdzie indziej. Gdzie i kiedy komukolwiek miałoby się przydać takie podejście? Dlaczego jest jakiś sens w tworzeniu obiektu i referencji do niego w dwóch innych klasach?

0

No ale to wszystko już zostało wytłumaczone. Co więcej takie podejście jest codziennością i to nie jest nic dziwnego. Korzysta się z takiego rzutowania tworząc interfejsy i wsadzając je np. jako argumenty metod. Polimorfizm jest wykorzystywany tak powszechnie, że możesz nawet nie zdawać sobie z tego sprawy.

Jeżeli natomiast chodzi o tracenie "rzeczy" w skutek takiej konwersji: klasy projektuje się tak, żeby to wszystko miało sens. Jeżeli nie chcesz tracić własności, to zrób je jako wirtualne i przedefiniuj w klasie pochodnej. Proste.

Dziedziczenie naprawdę się przydaje ale bardziej dziedziczenie po interfejsach niż zwykłych klasach abstrakcyjnych. Wiesz... w tak prostym przykładzie jaki masz rzeczywiście może tego nie być widać ale wyobraź sobie grę komputerową z samochodami. Masz tam klasę Car i marki Peugeot czy Volvo. Na trasie masz umieścić 20 samochodów. Tworzysz więc kontener dla klasy Car, a wirtualizacja sama sprawi, że program będzie wiedział jakie tam są samochody powtykane, niezależnie od tego czy dodasz new Peugeot() czy new Jelcz(). No nie wiem jak to inaczej wytłumaczyć. Musisz chyba zrobić coś większego żeby to zrozumieć.

Bez polimorfizmu musiałbyś tworzyć osobne kontenery dla poszczególnych marek na trasie.

0

@grzesiek51114: no mniej więcej to rozumiem. Jednak nadal jakiś niesmak mi tutaj pozostaje. Mam jeszcze jeden problem. Różnica między override a new . Mimo, że przeczytałem o tym artykułu na stronie microsoftu, to jakoś nie kumam tego new. Popatrzmy na przykład z ich strony.

using System;  
using System.Text;  

namespace OverrideAndNew  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            BaseClass bc = new BaseClass();  
            DerivedClass dc = new DerivedClass();  
            BaseClass bcdc = new DerivedClass();  

            // The following two calls do what you would expect. They call  
            // the methods that are defined in BaseClass.  
            bc.Method1();  
            bc.Method2();  
            // Output:  
            // Base - Method1  
            // Base - Method2  

            // The following two calls do what you would expect. They call  
            // the methods that are defined in DerivedClass.  
            dc.Method1();  
            dc.Method2();  
            // Output:  
            // Derived - Method1  
            // Derived - Method2  

            // The following two calls produce different results, depending   
            // on whether override (Method1) or new (Method2) is used.  
            bcdc.Method1();  
            bcdc.Method2();  
            // Output:  
            // Derived - Method1  
            // Base - Method2  
        }  
    }  

    class BaseClass  
    {  
        public virtual void Method1()  
        {  
            Console.WriteLine("Base - Method1");  
        }  

        public virtual void Method2()  
        {  
            Console.WriteLine("Base - Method2");  
        }  
    }  

    class DerivedClass : BaseClass  
    {  
        public override void Method1()  
        {  
            Console.WriteLine("Derived - Method1");  
        }  

        public new void Method2()  
        {  
            Console.WriteLine("Derived - Method2");  
        }  
    }  
}

Mimo, że wszystko jest opisane, to nie do końca rozumiem funkcjonalności słowa new.

0

O różnicach między override, a new napisano już chyba niemal wszędzie: http://lmgtfy.com/?q=c%23+override+vs+new [przy czym link nie jest złośliwością z mojej strony]
Poczytaj, bo ja już raczej odchodzę od komputera w niedzielny wieczór :)

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