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

konstruktor destruktor

VPS Starter Arubacloud
0 głosów
223 wizyt
pytanie zadane 14 sierpnia 2020 w C i C++ przez lujasjeden Użytkownik (860 p.)
algebraicExpression.h:

#include <iostream>

using namespace std;

class pWx
{
protected:
string userStringNum;
int degree;
int helper;
float *coefficients;

public:
pWx(string="0", int=0, int=0);
~pWx();
};

class pPx :public pWx
{
public:
pPx(string="0", int=0, int=0);
~pPx();
};

 

gather.cpp

#include <iostream>
#include "algebraicExpression.h"

using namespace std;

pWx::pWx(string uNS, int d, int h)
{
    userStringNum=uNS;
    degree=d;
    helper=h;
    cout<<"1 konstruktor zadzwonil";
    cout<<endl;
}
pWx::~pWx()
{
    cout<<"1 destruktor zadzwonil";
    cout<<endl;
}

pPx::pPx(string uNS, int d, int h)
{
    userStringNum=uNS;
    degree=d;
    helper=h;
    cout<<"2 konstruktor zadzwonil";
    cout<<endl;
}
pPx::~pPx()
{
    cout<<"2 destruktor zadzwonil";
    cout<<endl;
}
main

#include <iostream>
#include "algebraicExpression.h"
using namespace std;

int main()
{
    pWx Wx;
    pPx Px;
}

dlaczego output jest taki:

1 konstruktor zadzwonil
1 konstruktor zadzwonil
2 konstruktor zadzwonil
2 destruktor zadzwonil
1 destruktor zadzwonil
1 destruktor zadzwonil

tak ma byc? tzn ze 1 konstruktor i destruktor wywoluje sie 2 razy?

2 odpowiedzi

+2 głosów
odpowiedź 14 sierpnia 2020 przez profesorek96 Szeryf (91,420 p.)

Więc zacznijmy od początku. Konstruktor to specjalna metoda która wywołuje się w momencie tworzenia obiektu. To właśnie ona przygotowuje nasz obiekt do stanu użyteczności. W konstruktorze inicjalizujemy pola, alokujemy pamięć itp. Zaś destruktor to metoda która sprząta to co zostało po naszym obiekcie, głównie służy do zwalniania zarezerwowanych zasobów przez nasz obiekt w konstruktorze. Z zasady destruktor może być tylko jeden zaś konstruktorów może być mnóstwo (poczytaj o przeciążaniu metod).

Weźmy taki o to kod:

#include <iostream>
using namespace std;
class Klasa1
{
	public:
	Klasa1()
	{
		cout<<"Konstruktor Klasa1"<<endl;
	}
	~Klasa1()
	{
		cout<<"Destruktor Klasa1"<<endl;
	}
};
int main() {
	Klasa1 A;
	return 0;
}

Po wykonaniu naszego kodu na standardowe wyjście zostaną wypisane dwa napisy:

Konstruktor Klasa1
Destruktor Klasa1

Jest to jak najbardziej ok, tworzymy obiekt następnie z momentem zakończenia funkcji main obiekt ten jest usuwany.

Do naszego kodu dopiszmy kolejną klasę. Nazwijmy ją Klasa2. Następnie wprowadźmy relacje dziedziczenia. Klasa2 dziedziczy publicznie po Klasie1. Prezentuję tą sytuację poniższy kod:

#include <iostream>
using namespace std;
class Klasa1
{
	public:
	Klasa1()
	{
		cout<<"Konstruktor Klasa1"<<endl;
	}
	~Klasa1()
	{
		cout<<"Destruktor Klasa1"<<endl;
	}
};
class Klasa2:public Klasa1
{
	public:
	Klasa2()
	{
		cout<<"Konstruktor Klasa2"<<endl;
	}
	~Klasa2()
	{
		cout<<"Destruktor Klasa2"<<endl;
	}
};

int main() {
	Klasa2 A;
	return 0;
}

Uruchamiając ten kod naszym oczom ukażą się następujące napisy.

Konstruktor Klasa1
Konstruktor Klasa2
Destruktor Klasa2
Destruktor Klasa1

Jak widać najpierw wywoływany jest konstruktor klasy bazowej, a dopiero później klasy której obiekt tworzymy. Jest to jak najbardziej logiczne. Ponieważ klasa bazowa (Klasa1) to taki fundament na którym budujemy nasz dom to jest (Klase2). Natomiast rozbiórkę tak wybudowanego domu nie można zacząć od fundamentu (Klasa1) bo wszystko się nam na głowę zawali. Najpierw niszczymy to co zbudowaliśmy na naszym fundamencie czyli wywołujemy destruktor klasy Klasa2 zaś później dopiero sam fundament (Klasa1).

UWAGA!!!

Przeanalizujmy poniższy kod:

#include <iostream>
using namespace std;
class Klasa1
{
	public:
	Klasa1()
	{
		cout<<"Konstruktor Klasa1"<<endl;
	}
	~Klasa1()
	{
		cout<<"Destruktor Klasa1"<<endl;
	}
};
class Klasa2:public Klasa1
{
	public:
	Klasa2()
	{
		cout<<"Konstruktor Klasa2"<<endl;
	}
	~Klasa2()
	{
		cout<<"Destruktor Klasa2"<<endl;
	}
};

int main() {
	Klasa1 *A=new Klasa2();
	delete A;
	return 0;
}

Powyższy kod względem swojego poprzednika różni się zawartością funkcji main. Uruchamiając ten kod na naszym wyjściu nie zobaczymy wywołania dwóch destruktorów lecz tylko jednego. Tego z klasy bazowej.

Konstruktor Klasa1
Konstruktor Klasa2
Destruktor Klasa1

Dzieje się tak dlatego że nasz obiekt jest typu Klasa1. Do tak stworzonej zmiennej zostaje przypisany obiekt klasy potomnej. Jest to częsty przypadek kiedy chcemy wykorzystać tzw polimorfizm. Jeśli chcieli byśmy aby i w tym przypadku destruktory wywoływały się poprawnie należy zdefiniować w klasie bazowej (Klasa1) tak zwany destruktor wirtualny.

#include <iostream>
using namespace std;
class Klasa1
{
	public:
	Klasa1()
	{
		cout<<"Konstruktor Klasa1"<<endl;
	}
	virtual ~Klasa1()
	{
		cout<<"Destruktor Klasa1"<<endl;
	}
};
class Klasa2:public Klasa1
{
	public:
	Klasa2()
	{
		cout<<"Konstruktor Klasa2"<<endl;
	}
	~Klasa2()
	{
		cout<<"Destruktor Klasa2"<<endl;
	}
};

int main() {
	Klasa1 *A=new Klasa2();
	delete A;
	return 0;
}

Uruchamiając ten kod zobaczymy na standardowym wyjściu następujące dane.

Konstruktor Klasa1
Konstruktor Klasa2
Destruktor Klasa2
Destruktor Klasa1

 

komentarz 14 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)
a czy w konstruktorze w moim przypadku moge umiesicc w jakis sposob wskaznik coefficients? bo w nawiasie wydaje mi sie nienaturalne pisac new float[cos] ale nie wiem
komentarz 14 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)

o i czy majac np klase wirtualna

class Polynomial
{
virtual void gather()=0;
virtual void show()=0;
virtual void isInteger()=0;
}

robiac cos takiego:

class Wx :public Polynomial
{
virtual void gather();
virtual void show();
}

class Px :public Polynomial
{
virtual void gather();
virtual void show();
virtual void isInteger();
}

 

Wx odziedzicza tylko funckcje gather() i show() a Px odziedzicza wszystko?

Pytanie ogolne czy moge wybiorczo dziedziczyc rozne funkcje z klasy wirtualnej?

komentarz 15 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)

I jeszcze jedno 

main:

#include <iostream>
#include "polynomials.h"
using namespace std;

int main()
{
    Wx w;
    Px p;

    Polynomial *pointer;
    pointer=&w;
    pointer->gather();
    pointer->show();
    pointer=&p;
    pointer->gather();
    pointer->show();
}

polynomials.h:

#include <iostream>

using namespace std;

class Polynomial
{
public:
    virtual void gather()=0;
    virtual void show()=0;
};

class Wx :public Polynomial
{
protected:
    string userStringNum;
    int degree;
    int helper;
    float *coefficients;

public:
    virtual void gather();
    virtual void show();
    Wx(string="0", int=0, int=0);
    ~Wx();

};

class Px :public Wx
{
public:
    virtual void gather();
    virtual void show();
    Px(string="0", int=0, int=0);
    ~Px();
};

structors.cpp:

using namespace std;

Wx::Wx(string uNS, int d, int h)
{
    userStringNum=uNS;
    degree=d;
    helper=h;
    cout<<"1 konstruktor zadzwonil";
    cout<<endl;
}
Wx::~Wx()
{
    cout<<"1 destruktor zadzwonil";
    cout<<endl;
}

Px::Px(string uNS, int d, int h)
{
    userStringNum=uNS;
    degree=d;
    helper=h;
    cout<<"2 konstruktor zadzwonil";
    cout<<endl;
}
Px::~Px()
{
    cout<<"2 destruktor zadzwonil";
    cout<<endl;
}

i mam jeszczcze pliki gatherWx, gatherPx, showWx, showPx, w ktorych sa zdefiniowane funkcje wirtualne, output mam taki:

1 konstruktor zadzwonil
1 konstruktor zadzwonil
2 konstruktor zadzwonil
gatherWx zadzwonil
showWx zadzwonil
gatherPx zadzwonil
showPx zadzwonil
2 destruktor zadzwonil
1 destruktor zadzwonil
1 destruktor zadzwonil

powinienem chyba tego jakos uniknac czy nie?

zrobic wirtualny destruktor zeby wyrownac konstruktory i destruktory czy to tak nawet nie zadziala?

zmienic jakos tresc ktoregos z konstruktorow?

przepraszam jezeli to oczywiste pytania ale jestem jeszcze dosc poczatkujacy

 

1
komentarz 15 sierpnia 2020 przez profesorek96 Szeryf (91,420 p.)

 a czy w konstruktorze w moim przypadku moge umiesicc w jakis sposob wskaznik coefficients? bo w nawiasie wydaje mi sie nienaturalne pisac new float[cos] ale nie wiem

Nie rozumiem co chciałbyś zrobić.

Co do twojego pytania to nie ma czegoś takiego jak klasy wirtualne. Klasa może zawierać metody wirtualne i one dają możliwość wywołań polimorficznych. Natomiast jeśli metoda jest tak zwanie czysto wirtualna czyli np tak:

virtual void metoda()=0;

To jeśli klasa posiada chociaż jedną taką metodę to tak klasa staje się klasa abstrakcyjną. Jeśli będziemy dziedziczyć po tej klasie to musimy w klasie potomnej nadpisać wszystkie metody które są czysto wirtualne. Jeśli tego nie zrobimy to nasza klasa tj pochodna staje się również klasa abstrakcyjną. Nie jest możliwe stworzenie obiektu klasy abstrakcyjnej.

Natomiast jeśli pytasz czy da się wyłączyć jakieś metody z dziedziczenia to polecam poczytać ten temat:

https://cpp-polska.pl/post/dlaczego-unikamy-wielodziedziczeniaij

komentarz 15 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)
edycja 15 sierpnia 2020 przez lujasjeden

a czy w konstruktorze w moim przypadku moge umiesicc w jakis sposob wskaznik coefficients? bo w nawiasie wydaje mi sie nienaturalne pisac new float[cos] ale nie wiem

Bo w klasie Wx oraz Px mam wskaznik *coefficients, ktory bede wykorzystywal wtedy kiedy bede znal stopien wielomianu ktory wprowadzi uzytkownik. Przyklad: uzytkownik podaje degree=3 to robie new float [degree+1] i mam 4 szufladki na wspolczynniki (3 potega, 2potega, bez potegi, oraz wyraz wolny). A czy w konstruktorze jakos ten wskaznik ustawiac, nie wiem czy tak sie robi po prostu, jak tak to poprosze jak ma to wygladac.

 

Przeczytalem ten artykul ktory podlinkowales, zrozumialem z niego tak 2/3 tekstu, zgubilem sie troche przy kodzie o html, ale w jednym z ostatnich akapitow widzialem, ze OK jest robienie kilku klas abstrakcyjnych i wielodziedziczenie z tych klas. I to by mi sie baaardzo przydalo, zreszta taki zamysl mialem od poczatku, ale przeczytalem, ze tak nie mozna. Co potrzebuje jeszscze wiedziec to to czy majac np 5 metod wirtualnych w klasie abstrakcyjnej, jakas klasa pochodna moze odzedziczyc od niej tylko poszczegolne metody wirtualne, np 2, 3?

 

I teraz wpadlem na taki pomysl, zeby te wskazniki wszystkie dac do konstruktorow zamiast je w main pisac, robi sie tak? Usuwa sie pozniej wskazniki w destruktorze?

1
komentarz 15 sierpnia 2020 przez profesorek96 Szeryf (91,420 p.)

Szczerze mówiąc nie do końca rozumiem co chcesz osiągnąć. Jednak postaram ci uświadomić kilka rzeczy.

Jak najbardziej poprawne jest tak że masz wskaźnik w klasie i tworzysz w konstruktorze dynamiczną tablice. Obowiązkowo w destruktorze musisz ją zwolnić.

Zerknij na ten kod:

#include <iostream>
using namespace std;

class Klasa1
{
	private:
	float *t;
	int n;
	public:
	Klasa1(int d)
	{
		t=new float[d+1];
		n=d;
	}
	~Klasa1()
	{
		delete []t;
	}
};

int main() {
	Klasa1 A(5);
	return 0;
}

Jeśli jednak chciałbyś kopiować obiekty to musisz stworzyć konstruktor kopiujący.

komentarz 15 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)

a ok czyli w konstruktorze tez dac zainicjowanie wskaznikow, a czy dotyczy to rowniez tych wskaznikow:

Polynomial *pointer;
    pointer=&w;
    pointer->gather();
    pointer->show();
    pointer=&p;
    pointer->gather();
    pointer->show();

ze w konstruktorze Wx dac:

pointer=&w;

ale to chyba nie zadzaiala bo tego *pointer jeszcze nie ma bo to jest wskaznik Polynomial, jak to rozwiazac? tzn wywolywac to w mainie tylko? 

 

No i najwazniejsze dla mnie pytanie nadal czy majac np 5 metod wirtualnych w klasie abstrakcyjnej, jakas klasa pochodna moze odzedziczyc od niej tylko poszczegolne metody wirtualne, np 2, 3?

+1 głos
odpowiedź 14 sierpnia 2020 przez adrian17 Ekspert (344,100 p.)

Nazwy utrudniają czytanie, co tam zrobiłeś ;)

Ale tak, zgadza się:

pWx Wx;

Tutaj wywołuje się konstruktor tej klasy,

pPx Px;

A tutaj tej klasy i klasy bazowej.

Natomiast... ogólnie lepiej poczytaj o działaniu konstruktorów przy dziedziczeniu; ta cała duplikacja

    userStringNum=uNS;
    degree=d;
    helper=h;

powinna być tylko w jednym konstruktorze (klasy bazowej).

komentarz 15 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)
ok ale to tak ma byc czy powinienem jakos tego uniknac, zeby bylo tylko po 1 konstruktorze i destruktorze?
komentarz 15 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)
Px::Px(string uNS, int d, int h)
:Wx(uNS, d, h)
{
    //userStringNum=uNS;
    //degree=d;
    //helper=h;
    cout<<"2 konstruktor zadzwonil";
    cout<<endl;
}

tak to ma wygladac?? zobaczylem to w filmie Miroslawa Zelenta

dalem w komentarze to co bylo wczesniej, jezeli rozwiazanie jest dobre to zmaze to co w komentarzach

1
komentarz 15 sierpnia 2020 przez adrian17 Ekspert (344,100 p.)

tak to ma wygladac?

Tak :)

tak ma byc czy powinienem jakos tego uniknac

Tak ma być. Automatyczne wywoływanie konstruktorów klasy bazowej ma jak najbardziej sens i cel.

komentarz 15 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)
dzieki wielkie!

Podobne pytania

–4 głosów
0 odpowiedzi 439 wizyt
pytanie zadane 17 października 2017 w C i C++ przez p1erut Nowicjusz (120 p.)
0 głosów
2 odpowiedzi 232 wizyt
pytanie zadane 13 grudnia 2016 w C i C++ przez klap Początkujący (410 p.)
0 głosów
1 odpowiedź 719 wizyt

92,452 zapytań

141,262 odpowiedzi

319,077 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

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

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...