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

Tablica obiektów

Aruba Cloud PRO i VPS, Openstack, VMWare, MS Hyper-V
0 głosów
212 wizyt
pytanie zadane 23 maja 2020 w C i C++ przez Programmingc100 Bywalec (2,620 p.)

Witam wszystkich, mam pytanie odnośnie zapisu kodu w C ++, poniżej mam kod w którym tworzę tablicę wskaźników na obiekty a jeśli chciałbym utworzyć tablicę obiektów? Takie coś? 

Zwierze *tablica = new Zwierze[3];

 

#include <iostream>
#include <cstdlib>

using namespace std;

class Zwierze {
public:
    virtual void  daj_glos() {
       //
    }
};

class  Kot : public Zwierze {
public:
    void daj_glos() {
       cout<<"Miau "
    }
};

class Pies : public Zwierze {
public:
    void daj_glos() {
       cout<<"Woof "
    }
};

class Krowa : public Zwierze{
public:
    void daj_glos() {
        cout << "Muuuu";
    }
};

int main()
{
    Zwierze **tablica = new Zwierze*[3];

    tablica[0] = new Kot();
    tablica[1] = new Pies();
    tablica[2] = new Krowa();

    for (int i = 0; i<3; i++) {
        tablica[i]->daj_glos();
    }

    system("pause");
    return 0;
}

 

1
komentarz 23 maja 2020 przez DragonCoder Nałogowiec (36,500 p.)
Ale tworzysz dynamiczna tablice 2D, a chcesz uzyc 1D.  Wiec jaki to ma sens? Po zs tym alokujesz pamiec przez wskaznik, ale jej nie zwalniasz. Po to masz vector w jezyku cpp i polecam sie z nim zapoznac

4 odpowiedzi

+2 głosów
odpowiedź 25 maja 2020 przez profesorek96 Szeryf (91,460 p.)
wybrane 13 lipca 2020 przez Programmingc100
 
Najlepsza

Tworząc tablice dynamicznie 1 wymiarową potrzebujesz wskaźnika o danym typie. Za pomocą operatora new alokujesz pamięć. Operator new zwraca adres pierwszego komórki pamięci. Typ wskaźnika określa o ile bajtów należy przeskoczyć by obejmować kolejną komórę pamięci.

Np.

int *tab=new int[3];

Powyższy zapis tworzy tablice dwu wymiarową. Jeśli chcieli byśmy stworzyć tablicę wskaźników. Tablica ta przechowuje nie wartości a adresy. Wtedy należy użyć konstrukcji wskaźnik na wskaźnik. Tablice wskaźników są często używane, jeśli chcieli byśmy stworzyć tablice dwu wymiarową dynamiczną.

//tworzenie tablicy 2d 3x3
int **tab=new int*[3];//tworzymy tablicę wskaźników
for(int i=0;i<3;i++)
{
    tab[i]=new int[3];//do każdego z wskaźników alokujemy pamięć
}

Oczywiście w przypadku tablicy jednowymiarowej wystarczy użyć funkcji delete [] by zwolnić pamięć. W przypadku tablicy 2d wykonali byśmy to w ten sposób.

for(int i=0;i<3;i++)
{
    delete [] tab[i];//zwalniamy pamięć na jaką wskazuje każdy z wskaźników
}
//teraz usuwamy właściwą tablice wskaźników
delete [] tab;

Jeśli chodzi o twój program to mamy do czynienia z zjawiskiem zwanym polimorfizmem. Polimorfizm dynamiczny może tylko i wyłącznie zachodzić wtedy kiedy używamy wskaźników. Na logikę Zwierzę to nie Kot ale Zwierze należy do tej samej rodziny co Kot. Dlatego tutaj należy używać wskaźników. Twój kod powinien wyglądać tak, zapominasz o zwalnianiu pamięci.

#include <iostream>
#include <cstdlib>
 
using namespace std;
 
class Zwierze {
public:
    virtual void  daj_glos() {
       //
    }
};
 
class  Kot : public Zwierze {
public:
    void daj_glos() {
       cout<<"Miau ";
    }
};
 
class Pies : public Zwierze {
public:
    void daj_glos() {
       cout<<"Woof ";
    }
};
 
class Krowa : public Zwierze{
public:
    void daj_glos() {
        cout << "Muuuu";
    }
};
 
int main()
{
    Zwierze **tablica = new Zwierze*[3];
 
    tablica[0] = new Kot();
    tablica[1] = new Pies();
    tablica[2] = new Krowa();
 
    for (int i = 0; i<3; i++) {
        tablica[i]->daj_glos();
    }
    
    //sprzatamy
    for(int i=0;i<3;i++)
    {
    	delete[] tablica[i];
    }
    delete []tablica;
 
    //system("pause");
    return 0;
}

Polimorfizm może istnieć dzięki relacji zwanej dziedziczeniem. To samo co wyżej możesz zrobić z wykorzystaniem kontenerów vector.

#include <iostream>
#include <cstdlib>
#include <vector>
using namespace std;
 
class Zwierze {
public:
    virtual void  daj_glos() {
       //
    }
};
 
class  Kot : public Zwierze {
public:
    void daj_glos() {
       cout<<"Miau ";
    }
};
 
class Pies : public Zwierze {
public:
    void daj_glos() {
       cout<<"Woof ";
    }
};
 
class Krowa : public Zwierze{
public:
    void daj_glos() {
        cout << "Muuuu";
    }
};
 
int main()
{
	vector<Zwierze *> tablica;
	tablica.push_back(new Kot());
	tablica.push_back(new Pies());
	tablica.push_back(new Krowa());
    
    for(int i=0;i<tablica.size();i++)
    {
    	tablica[i]->daj_glos();
    }
    
    return 0;
}

 

+2 głosów
odpowiedź 23 maja 2020 przez j23 Mędrzec (191,020 p.)

Takie coś? 

Takie coś jest OK, jeśli chcesz mieć tablicę obiektów klasy Zwierze. Ta tablica nie ma zastosowania w kodzie, który podałeś. Polimorfizm opiera się na wskaźniku/referencji. Innej opcji nie ma.

+1 głos
odpowiedź 23 maja 2020 przez mokrowski Mędrzec (155,400 p.)

Prawie dobrze. Tylko w kodzie który podałeś, są wycieki pamięci i trochę niezręczności:

#include <iostream>
#include <cstdlib>

using namespace std;

class Zwierze {
public:
    virtual void  daj_glos() const = 0;
    virtual ~Zwierze() {}
};

class  Kot : public Zwierze {
public:
    void daj_glos() const override {
       cout << "Miau ";
    }
};

class Pies : public Zwierze {
public:
    void daj_glos() const override {
       cout << "Woof ";
    }
};

class Krowa : public Zwierze{
public:
    void daj_glos() const override {
        cout << "Muuuu";
    }
};

int main()
{
    Zwierze **tablica = new Zwierze*[3];

    tablica[0] = new Kot();
    tablica[1] = new Pies();
    tablica[2] = new Krowa();

    for (int i = 0; i < 3; ++i) {
        tablica[i]->daj_glos();
    }

    for (int i = 0; i < 3; ++i) {
        delete tablica[i];
    }
    delete [] tablica;

    system("pause");
    return 0;
}

 

2
komentarz 23 maja 2020 przez tkz Nałogowiec (42,000 p.)
IMO tutaj chyba nie ma to aż tak dużego znaczenia, bo i tak program kończy się na wypisaniu, a zwolnieniem pamięci zajmie się system.
1
komentarz 23 maja 2020 przez mokrowski Mędrzec (155,400 p.)
Jak najbardziej w takich przypadkach także należy zwolnić zasoby.
1
komentarz 23 maja 2020 przez tkz Nałogowiec (42,000 p.)
Dlaczego? Nie mówię, że dbanie o pomięć jest zbędne, ale dlaczego akurat tutaj należy ją zwolnić?
2
komentarz 23 maja 2020 przez mokrowski Mędrzec (155,400 p.)
W całej inżynierii oprogramowania, jest zasada by pozostawić stan systemu/modułu/biblioteki/aplikacji taki jak przed wykonaniem operacji. Szczególnie zasada ta kłania się w przypadku testów lub uruchomienia w różnych środowiskach (wirtualne, kontenery, testy itp). Jeśli tego nie robisz, to popełniasz błąd w sztuce. Np. czy wiesz (bo ja nie jestem pewien), jak zadziała taka aplikacja w systemie GNU/Linux z uclibc na platformie na której nie ma zarządzania pamięcią (tak, i na takiej można uruchomić takiego "dziwnego GNU/Linux")? Albo czy działanie programu zaliczy sprawdzarka która weryfikuje zużyte zasoby lub stan po wykonaniu?

Zasada skauta (zostawiam stan jaki zastałem lub ... "lepszy"), to jedna z podstawowych filozofii dobrze wykonanej pracy :-)
1
komentarz 23 maja 2020 przez tkz Nałogowiec (42,000 p.)
Holistycznie na to patrząc masz rację. Skupiłem się na tworze Microsoftu.
0 głosów
odpowiedź 24 maja 2020 przez Programmingc100 Bywalec (2,620 p.)

Czyli nie można napisać tablicy obiektów  z różnych klas nie używając do tego wskaźników? Co najwyżej w ten sposób:

Zwierze tablica[3] = {Kot(), Pies(), Krowa()};

for (int i = 0; i < 3; i++) 
cout << "Głos:" << tablica[i].daj_glos() << endl;

Ale wtedy nie otrzymam nic, bo tylko to co jest w metodzie wirtualnej.

1
komentarz 24 maja 2020 przez tkz Nałogowiec (42,000 p.)
To się nawet nie skompiluje.
1
komentarz 24 maja 2020 przez j23 Mędrzec (191,020 p.)

@Programmingc100,

Co najwyżej w ten sposób:

Ale to cały czas jest tablica obiektów klasy Zwierze i daj_glos będzie w wersji zaimplementowanej w tej klasie.

 

PS. dyskusje prowadzimy w komentarzach.

Podobne pytania

0 głosów
1 odpowiedź 110 wizyt
pytanie zadane 5 kwietnia 2021 w C i C++ przez Paweł Środek Nowicjusz (200 p.)
0 głosów
1 odpowiedź 195 wizyt
pytanie zadane 7 maja 2020 w C i C++ przez Programmingc100 Bywalec (2,620 p.)
0 głosów
1 odpowiedź 418 wizyt

91,278 zapytań

139,942 odpowiedzi

315,130 komentarzy

60,722 pasjonatów

Motyw:

Akcja Pajacyk

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

Sklep oferujący ćwiczenia JavaScript, PHP, rozmowy rekrutacyjne dla programistów i inne materiały

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

...