Dziedziczenie - podejrzane wywolanie destruktorow ?

Odpowiedz Nowy wątek
en2
2016-02-17 20:15
en2
0

Witam,

Pracuje nad 2 klasami. 1 z nich jest klasa bazowa, ktora obrazuje liste jako zbior wartosci, posiadajaca metody do wyswietlania jej elementow. Klasa 2 jest juz konkretna realizacja listy, wiec dziedziczy publicznie po klasie lista_t. Oto definicje i implementacje klas.

class lista_t
{
protected:
    std::string * wsk_nazwa_skrocona;
    int wybrany_element;

public:
    lista_t();
    virtual ~lista_t();

    std::string nazwa_skrocona();
};

lista_t::lista_t()
{
    std::cout << "Konstruktor klasa bazowa, " << "ustawiam zmienna indeksu z " << wybrany_element << " na " << 0 << std::endl;
    wybrany_element = 0;
}

lista_t::~lista_t()
{
    std::cout << "Destruktor klasa bazowa" << std::endl;
}

std::string lista_t::nazwa_skrocona()
{
    std::cout << "metoda nazwa skrocona " << wsk_nazwa_skrocona << " " << wybrany_element << std::endl;
    return wsk_nazwa_skrocona[ wybrany_element ];
}

namespace stopien
{
    enum lista { alfa, bravo };

    class stopien_t
        : public lista_t
    {

    public:
        stopien_t( stopien::lista st );
        ~stopien_t();
    };

    stopien_t::stopien_t( stopien::lista st )
    {
        std::cout << "Konstruktor klasa pochodna, ustawiam zmienna indeksu z " << wybrany_element << " na " << st << std::endl;

        wybrany_element = st;

        wsk_nazwa_skrocona = new std::string[ 2 ];

        std::cout << "Konstruktor klasa pochodna, przydzielam pamiec - przydzielono adres " << wsk_nazwa_skrocona << std::endl;

        wsk_nazwa_skrocona[ 0 ] = "ALFA";
        wsk_nazwa_skrocona[ 1 ] = "BRAVO";
    }

    stopien_t::~stopien_t()
    {
        std::cout << "Destruktor klasa pochodna" << std::endl;
        delete[] wsk_nazwa_skrocona;
    }
}

W pliku main mam cos takiego


int main()
{
    lista_t nowa_lista = stopien::stopien_t( stopien::bravo );

    system( "pause" );
    return 0;
}

Wynik:

Konstruktor klasa bazowa, ustawiam zmienna indeksu z 17174570 na 0
Konstruktor klasa pochodna, ustawiam zmienna indeksu z 0 na 1
Konstruktor klasa pochodna, przydzielam pamiec - przydzielono adres 00CC8544
Destruktor klasa pochodna
Destruktor klasa bazowa
Press any key to continue . . .

Dlaczego od razu po utworzeniu obiektu, wywolywane sa obydwa destruktory? (po nacisnieciu czegokolwiek poprawnie dziala destruktor klasy bazowej)

Pozostało 580 znaków

2016-02-17 20:21
Moderator

Rejestracja: 16 lat temu

Ostatnio: 3 minuty temu

1

Nie chce mi sie trochę analizować tego kodu bo niepotrzebnie wrzucasz taki skomplikowany przykład mogłeś dać 5 linijek Proof-of-Concept. To co widać na pierwszy rzut oka to przekazywanie obiektów a nie referencji do nich. C++ to nie Java i domyślnie przekazuje KOPIE. Więc jak masz:
stopien_t( stopien::lista st );
to ta lista zostanie SKOPIOWANA i siłą rzeczy przy wychodzeniu z tego kontruktora ta kopia zostanie zniszczona i odpali się destruktur.


Masz problem? Pisz na forum, nie do mnie. Nie masz problemów? Kup komputer...
stopien::lista - to enum :/ - _13th_Dragon 2016-02-17 20:38
@_13th_Dragon o faktycznie :/ pogratulować tutaj mogę nazwenictwa w takim razie bo nie spdziewałbym sie :D - Shalom 2016-02-17 20:47
Ja też najpierw pomyślałem że pozmieniał nazwy (ale nie wszędzie) i wkleił, dopiero po chwili się dopatrzyłem. Nazewnictwo - urwał pergole. - _13th_Dragon 2016-02-17 21:15

Pozostało 580 znaków

2016-02-17 20:42

Rejestracja: 14 lat temu

Ostatnio: 3 dni temu

1

To podstawowy koncept dziedziczenia.
Student pochodzi od Człowieka, więc aby mieć Studenta najpierw trzeba "wyhodować" Człowieka a później na bazie umiejętności człowieka dodajemy legitymacje studencką i index i już mamy Studenta.

P.S.
Wg mnie to lepsze rozwiązanie:

class lista_t
  {
   protected:
   size_t choice;
   public:
   setChoice(size_t choice) { if(names(choice)) this.choice=choice; }
   size_t getChoice()const { return choice; }
   lista_t(size_t choice):choice(0) { setChoice(choice); }
   virtual ~lista_t();
   virtual const char *names(size_t choice)=0; // ewentualnie { return nullptr; } 
  };

class stopien_t
  {
   public:
   virtual const char *names(size_t choice)
     {
      static const char *tb[]={"ALFA","BRAVO"};
      return choice<sizeof(tb)/sizeof(*tb)?tb[choice]:nullptr;
     }
  };

Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
edytowany 2x, ostatnio: _13th_Dragon, 2016-02-17 21:27

Pozostało 580 znaków

2016-02-17 22:49

Rejestracja: 8 lat temu

Ostatnio: 52 minuty temu

2

Ta linia:

lista_t nowa_lista = stopien::stopien_t( stopien::bravo );

1) tworzy nowy tymczasowy, nienazwany obiekt stopien_t z argumentem konstruktora o wartości "stopien::bravo" (enum)

stopien::stopien_t( stopien::bravo );

2) wywołuje przypisanie tego obiektu przez konstruktor kopiujący o ile dobrze pamiętam:

lista_t nowa_lista = ?

3) kasuje z pamięci obiekt tymczasowy z pkt. 1

4) po pause usuwany jest obiekt nazwany "nowa_lista":

lista_t nowa_lista

Szacuje się, że w Polsce brakuje 50 tys. programistów
2 i 3 dobrze, ale gdyby użył dobrego typu to byłaby to zwykła inicjalizacja bez kopii. - kq 2016-02-18 05:29

Pozostało 580 znaków

kq
2016-02-18 05:31
kq
Moderator C/C++

Rejestracja: 6 lat temu

Ostatnio: 19 godzin temu

Lokalizacja: Szczecin

2
std::cout << "Konstruktor klasa bazowa, " << "ustawiam zmienna indeksu z " << wybrany_element << " na " << 0 << std::endl;

To jest technicznie UB - odczytujesz niezainicjalizowaną zmienną.

Do obiektu typu Base przypisujesz Derived. To jest object slicing: http://stackoverflow.com/ques[...]274626/what-is-object-slicing
Zakładam, że to też jest Twój problem.


Pozostało 580 znaków

Odpowiedz

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