Dziedziczenie prywatne, referencja

0

Dzień Dobry,

Zaczynam kompletnie dopiero dziedziczenie i miałbym prośbe, czy ktoś mógłby mi wskazać czemu występuje błąd, co robię źle, i dlaczego, chciałbym bardzo perfekcyjnie zrozumieć temat, nie chcę kopiować bezmyślnie kodu. Byłbym dozgonnie wdzięczny za pomoc.

#include <iostream>
using namespace std;

inline void czytaj(int *czyt, int dl) {
	for (int i = 0; i < dl; cout << *(czyt + i) << " ", i++);
}

class CTablicaInt {
protected:
	int * wsk;
	int rozmiar;
	void inicjuj() {
		wsk = new int[rozmiar];
		for (int i = 0; i < rozmiar; wsk[i] = 0, i++);
	}
	inline bool sprawdz();
public:
	CTablicaInt(int roz);
	CTablicaInt(int *wskaz, int roz);
	CTablicaInt(const CTablicaInt & s);
	int & operator [](int i) {
		return wsk[i];
		cout << "DZIALA OPERATOR [] " << endl;
	} // operator []
	CTablicaInt & operator =(const CTablicaInt &p);
	int get_rozmiar() {
		return rozmiar;
	}
	friend std::ostream & operator <<(std::ostream &s, const CTablicaInt &a) {
		s << "Jestem operatorem << \n rozmiar : " << a.rozmiar << "\n";
		for (int i = 0; i < a.rozmiar; i++) {
			s << *(a.wsk + i) << " ";
		}
		s << "\n";
		return s;
	} // operator <<
	void sortuj();
	~CTablicaInt();
};

class CStosInt: private CTablicaInt {
protected:
	CTablicaInt &y;
	//CTablicaInt *y;
public:

	CStosInt(CTablicaInt &z) : CTablicaInt(z), y(z) {};
	    //    CStosInt( CTablicaInt &z):CTablicaInt(z){y=&z;};

	bool czy_pusty();
	bool czy_pelny();
	void wloz(int a); // pierwszy wchodzi ostatni wychodzi ! FILO !
	void zdejmij();
	void wyswietl(){
		cout << y;
	}
	~CStosInt();
};
CStosInt :: ~CStosInt(){
	delete &y;
}

void CStosInt::wloz(int a) {
	int *nowy = new int[y.get_rozmiar() + 1];
	for (int i=0 ; i < rozmiar ; i++){
		nowy [i] = y[i];
	}
	CTablicaInt c = (nowy,y.get_rozmiar()+1);
	y = c;
	c.~CTablicaInt();
	
}

int main() {
	int tab[] = { 1, 2, 3, 4, 664, 23, 2313, 43, 234, 23423, 232 };
	CTablicaInt a(tab, 5);
	CStosInt b(a);
	b.wloz(15);
	b.wyswietl();
	return 0;
}

CTablicaInt::~CTablicaInt() {
	delete wsk;
}

CTablicaInt & CTablicaInt::operator =(const CTablicaInt &p) {
	if (this == &p) {
		return *this;
	}
	delete wsk;
	rozmiar = p.rozmiar;
	wsk = new int[rozmiar];
	for (int i = 0; i < p.rozmiar; i++) {
		*(wsk + i) = *(p.wsk + i);
	}
	cout << "OPERATOR PRZYPISANIA" << endl;
	return *this;
}

CTablicaInt::CTablicaInt(const CTablicaInt & s) {
	wsk = s.wsk;
	rozmiar = s.rozmiar;
	cout << "KONSTUKTOR KOPIUJACY : " << endl;
}

CTablicaInt::CTablicaInt(int *wskaz, int roz) {
	rozmiar = roz;
	inicjuj();
	for (int i = 0; i < roz; i++) {
		*(wsk + i) = *(wskaz + i);
	}
	cout << "JESTEM KONSTRUKTOREM 2" << endl;
}
0

Jaki błąd?

0

och przepraszam, jest błąd z alokacją pamieci, pojawia się przy inicjalizacji konstruktora z klasy pochodnej.

*** glibc detected *** ./stos: double free or corruption (fasttop): 0x0000000000a56050 ***
======= Backtrace: =========
/lib/libc.so.6(+0x78e66)[0x7fa6b7c58e66]
./stos[0x400d4f]
./stos[0x400abe]
./stos[0x400bdc]
/lib/libc.so.6(__libc_start_main+0xed)[0x7fa6b7c0138d]
./stos[0x4008f9]
======= Memory map: ========
0

Tak na pierwszy rzut oka:

  1. konstruktor kopiujący w klasie CTablicaInt jest zły, spowoduje, że destruktor będzie wywołany co najmniej dwa razy(dla kopii i oryginału obiektu). Co za tym idzie operator delete zostanie wywołany dwa razy dla tej samej tablicy. W tym konstruktorze powinieneś przekopiować zawartość tablicy, a nie tylko wskaźnik. Aktualnie ten konstruktor nie ma sensu, bo zachowuje się tak samo jak domyślny.

  2. całe to dziedziczenie tu nie ma sensu, skoro i tak masz agregację w tym stosie(CTablicaInt &y;) Wywal tą zmienną z klasy i używaj tego co odziedziczyłeś - w końcu po coś to dziedziczenie tam masz. Chociaż z drugiej strony, akurat w tym przypadku agregacja byłaby lepszym rozwiązaniem niż dziedziczenie. Stos raczej korzysta z tablicy, a nie jest szczególnym przypadkiem tablicy.

  3. funkcja wloz też jest źle napisana, całkowicie źle napisana. Linijka CTablicaInt c = (nowy,y.get_rozmiar()+1); to jakaś herezja, jawne wywołanie destruktora to koszmar. NIGDY nie wywołuj destruktora jawnie(teraz dla c destruktor zostanie wywołany 2 razy i masz zonk). Znam tylko jedną sytuację, gdzie może to być konieczne, ale nigdy się z nią nie spotkałem i na tym poziomie Twojej znajomości zarządzania pamięcią na pewno na nią nie trafisz(chodzi konkretnie o placement new).

Zmianą rozmiaru tablicy powinna się zajmować klasa CTablicaInt, a nie CStosInt.

0
  1. Hmmm faktycznie, czasem mój brak myślenia zaskakuje, ale cóż człowiek się uczy.
    Zmieniłem na :
		CTablicaInt(const CTablicaInt & s):rozmiar(s.rozmiar){
		wsk = new int [rozmiar];
		for (int i=0; i < rozmiar; wsk[i] = s.wsk[i], i++);
	}
	}
  1. Zadanie skupia się na przećwiczeniu dziedziczenia prywatnego, by zablokować operacje niedozwolone (sortowanie, przypisywanie, etc, etc) z CTablicaInt. Kompletnie żle zrozumiałem zagadnienie, myślałem, że muszę mieć tą referencje do CTablicaInt do której będzie przypisywany przyjęty obiekt CTablicaInt i dopiero wtedy mogę coś z tym robić.
    Poprawione na :
class CStosInt: private CTablicaInt {
public:
	CStosInt(CTablicaInt &x) : CTablicaInt(x) {};
	bool czy_pusty();
	bool czy_pelny();
  1. To mam kompletnie spieprzone przyznaje i z tym dam sobie radę, tak myśle.

Dzięki jeszcze raz za pomoc :) I pozdrawiam .

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