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

question-closed Wzorzec projektowy Prototyp a dwa konstruktory i metody

+1 głos
179 wizyt
pytanie zadane 26 października 2019 w C i C++ przez AuriattaDev Początkujący (390 p.)
zamknięte 26 października 2019 przez AuriattaDev

Hej wszystkim,
próbuję ogarnąć wzorzec projektowy prototyp i nie mogę pojąć w nim pewnych aspektów, mianowicie coś takiego:

class Monster
{
public:
  virtual ~Monster() {}
  virtual Monster* clone() = 0;

  // Other stuff...
};


class Ghost : public Monster {
public:
  Ghost(int health, int speed)
  : health_(health),
    speed_(speed)
  {}

  virtual Monster* clone()
  {
    return new Ghost(health_, speed_);
  }

private:
  int health_;
  int speed_;
};

Czy wywołanie po dwukropku zmiennych health i speed dodaje do klasy bazowej te zmienne? Wiem że jest to narzucenie wartości klasie bazowej ale przecież nie ma w niej tych zmiennych.

A druga sprawa w innym przykładzie występuje w klasie pochodnej coś takiego:
 

 Dlugopis(const int dlugosc, const QString kolor, int paczka = 0 )
        : dlugosc( dlugosc ), kolor( kolor ), paczka(new int(paczka))
    {
    }

    Dlugopis( const Dlugopis & kopia )
        : dlugosc( kopia.dlugosc )
        , kolor( kopia.kolor )
    {
        this->paczka = new int(kopia.getPaczka());
    }

w klasie pochodnej i teraz nie rozumiem, czemu ta klasa ma dwa konstruktory? Rozumiem że jedna jest od kopiowania ale czy ktoś mógłby wytłumaczyć dlaczego to tak wygląda?

komentarz zamknięcia: Problem rozwiązany

2 odpowiedzi

+2 głosów
odpowiedź 26 października 2019 przez mokrowski VIP (146,880 p.)

Czy wywołanie po dwukropku zmiennych health i speed dodaje do klasy bazowej te zmienne?

Takie inicjowanie, nazywane jest listą inicjalizacyjną. Dzięki temu podejściu możesz:

1. Inicjować atrybuty które w klasie są stałe (w samym ciele konstruktora nie możesz atrybutów stałych inicjować)

2. Wykonać tylko 1 raz inicjalizację atrybutu bez konieczności wywoływania jego konstruktora. Gdybyś inicjował w ciele konstruktora, dany atrybut konstruowany będzie 2 razy. Raz na liście i następny raz w ciele konstruktora.

3. Kolejność inicjalizacji atrybutów, jest taka jak wymienione kodzie klasy a nie taka jak na liście inicjalizacyjnej. Kompilatory (a nie IDE), dają informację o inicjalizacji w liście w innej kolejności niż w klasie jeśli uruchomisz ostrzeżenia.

Konstruktor kopiujący implementujesz jeśli kopiowanie obiektu jest nietrywialne. Jednym z powodów (choć nie jedynym) może być atrybut w postaci wskaźnika na dynamicznie alokowane dane.

Przykład prototypu jaki podałeś, jest ... taki sobie (oględnie). Można zauważyć że w zasadzie dubluje konstruktor (więc po co?). Prototypy stosuje się gdy obiekt poddawany przetwarzaniu, posiada jakiś bardzo złożony stan który nie jest obsługiwany przez konstruktor kopiujący (lub konstruktor klasy), lub nie możesz mieć/nie chcesz takiego konstruktora. Często by "zamrozić stan" obiektu lub mieć "taki sam jak..." przed wykonaniem ryzykownej operacji (np. niestabilnych numerycznie obliczeń). 

komentarz 26 października 2019 przez AuriattaDev Początkujący (390 p.)
W zasadzie był to przykład z internetu, który chyba w krótki sposób miał pokazać że coś takiego jak konstruktor kopiujący istnieje, niestety nie znajdował się tam jakiś głębszy opis.
Dziękuje za wskazówki, wszystko teraz zdaje się być jasne : )
+1 głos
odpowiedź 26 października 2019 przez obl Maniak (51,120 p.)

Czy wywołanie po dwukropku zmiennych health i speed dodaje do klasy bazowej te zmienne? Wiem że jest to narzucenie wartości klasie bazowej ale przecież nie ma w niej tych zmiennych.

 Nie w ten sposób inicjalizujesz w listingu istniejące pola klasy wartościami.

czemu ta klasa ma dwa konstruktory?

 Konstruktor kopiujący służy do kopiowania wartości. Stosuje się go, gdy w klasie masz dynamicznie przydzielaną pamięć. W takim przypadku trzeba napisać taki konstruktor. W przeciwnym przypadku wystarczy domyślny konstruktor kopiujący.

Drugi (a w zasadzie pierwszy) konstruktor inicjalizuje klasę podanymi na wejście zmiennymi. W ten sposób w C++ możesz deklarować kilka różnych konstruktorów, które na podstawie liczby pól oraz ich typów będą w stanie poprawnie utworzyć nowy obiekt klasy.

komentarz 26 października 2019 przez AuriattaDev Początkujący (390 p.)

Nie w ten sposób inicjalizujesz w listingu istniejące pola klasy wartościami.

Rozumiem, czyli jest to takie skrócenie kodu? Żeby nie pisać np:

Ghost(int health, int speed)
  { health_ = health; speed_ = speed; }

A mogę dodać zwykłą metodę do klasy pochodnej, którą będzie można wywołać ze wskaźnika? Pytam ponieważ mi się nie udało, kompilator nie widzi tej metody. Tylko jeśli zadeklaruje virtualną metodę w klasie bazowej i nadpiszę w pochodnej..

komentarz 26 października 2019 przez obl Maniak (51,120 p.)

Tak dokładnie. Warto też robić to w kolejności w jakiej w klasie te pola się znajdują bo czasami to ma znaczenie i niektóre IDE informują o tym.

w virtualnej klasie zrób czysto wirtualną metodę:

virtual method() => 0;

a w klasie pochodnej stwórz metodę:

virtual method() {
    // tutaj twój kod
}

wtedy nie powinno być problemów

 

P.S.

Jak chcesz to tutaj opisałem trochę różnych wzorców projektowych: https://www.obliczeniowo.com.pl/827

1
komentarz 26 października 2019 przez AuriattaDev Początkujący (390 p.)
Rozumiem już, dziękuje Ci bardzo za pomoc ^ ^. Chętnie zerknę

Podobne pytania

0 głosów
0 odpowiedzi 218 wizyt
pytanie zadane 22 stycznia 2017 w C# przez timrh Mądrala (6,050 p.)
0 głosów
1 odpowiedź 112 wizyt
0 głosów
1 odpowiedź 293 wizyt
pytanie zadane 7 maja 2017 w C i C++ przez sofnir Gaduła (4,690 p.)

86,427 zapytań

135,188 odpowiedzi

300,309 komentarzy

57,184 pasjonatów

Motyw:

Akcja Pajacyk

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

Oto dwie polecane książki warte uwagi. Pełną listę znajdziesz tutaj.

...