Dziedziczenie - podejrzane wywolanie destruktorow ?

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)

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.

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;
     }
  };
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 );
  1. wywołuje przypisanie tego obiektu przez konstruktor kopiujący o ile dobrze pamiętam:
lista_t nowa_lista = ?
  1. kasuje z pamięci obiekt tymczasowy z pkt. 1

  2. po pause usuwany jest obiekt nazwany "nowa_lista":

lista_t nowa_lista
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/questions/274626/what-is-object-slicing
Zakładam, że to też jest Twój problem.

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