Dziedziczenie, Asocjacja, Agregacja, Utility, Friend

0

Witam, proszę o pomoc.

Najpierw wrzucę cząstkę kodu w moim programie :

/////////// plik klasy.h /////////////////////////////////////
#ifndef KLASY_H
#define KLASY_H

class B;

class A
{
private:
	int a;
	B *agr1;
public:
	A();
	~A();
};

class B : public A
{
private:
	int b;
public:
	B();
	~B();
};


#endif
/////// plik klasa.cpp ///////////////////////////////////////////
#include<iostream>
using namespace std;

#include"klasy.h"

A::A()
{
	a = 1;
	agr1 = new B;
}
A::~A()
{
	delete agr1;
}

B::B()
{

}
B::~B()
{
}
//////////// plik main.cpp /////////////////////////////////
#include<iostream>
#include"klasy.h"

using namespace std;

int main()
{
A *A1;
A1 = new A;

delete A1;

system("pause");
return 0;
}

Wszystko się kompiluje ale w momencie gdy chcę włączyć program jest error i otwiera się biblioteka malloc.c
Chodzi o to ze w klasa B dziedziczy klasę A, i w klasie A jest obiekt klasy B. Osobiście uważam ze nie ma w tym logiki ale niestety muszę to umieć żeby zaliczyć Programowanie Obiektowe i wiem ze takie głupie dziedziczenie z agregacją jest możliwe.
W załączniku dodaje .jpg jak powinien wyglądać cały program oraz poniżej wkleję cały kod programu.

////////////// plik klasa.h //////////////////////////////////
#ifndef KLASA_H
#define KLASA_H

#include<iostream>
using namespace std;

class B;
class C;
class D;
class E;

class H
{
public:
	static double get_pi() { return pi; }
	static double get_e() { return e; }
private:
	static double pi;
	static double e;
};

class A : public H
{
private:
	int tab[3];
	B *agr1;
	C *agr2;
	D *agr3;
	E *agr4;
public:
	A();
	virtual ~A();
	A(A &);
	int &operator[](int ktory) { return tab[ktory]; }
	A &operator=(A &);
	friend ostream &operator<<(ostream &stream, A &p);
	friend istream &operator>>(istream &stream, A &p);
	A operator+(A );
	friend A operator-(A , A);
};

class B : public A
{
private:
	int b;
public:
	B() { b = 1; }
	virtual ~B() { }
	int get_b() { return b; }
	void set_b(int x) { b = x; }
	friend class F;
};


class C : public virtual B
{
private:
	int c;
public:
	C() { c = 2; }
	virtual ~C() { }
	int get_c() { return c; }
	void set_c(int x) { c = x; }

};


class D : public virtual B
{
private:
	int d;
public:
	D() { d = 3; }
	virtual ~D() { }
	int get_d() { return d; }
	void set_d(int x) { d =x; }
};


class E : public C, public D
{
private:
	int e;
public:
	E() { e = 4; }
	virtual ~E() { }
	int get_e() { return e; }
	void set_e(int x) { e = x; }

};


class F
{
private:
	int f;
public:
	F() { f = 5; }
	~F() { }
	int get_f() { return f; }
	void set_f(int x) { f = x; }
	void przypisz(B p);
};


class G
{
private:
	C *m_C;
public:
	void Ustaw_Relacje(C *p_C) { m_C = p_C; }
};


#endif
///////////////// plik klasa.cpp //////////////////////////
#include<iostream>
using namespace std;

#include"klasa.h"

double H::pi = 3.14;
double H::e = 2.71;

A::A()
{
	tab[0] = 1;
	tab[1] = 2;
	tab[2] = 3;

	agr1 = new B;
	agr2 = new C;
	agr3 = new D;
	agr4 = new E;
}
A::~A()
{
delete agr1;
delete agr2;
delete agr3;
delete agr4;
}
A::A(A &wzor)
{
	agr1 = new B;
	agr2 = new C;
	agr3 = new D;
	agr4 = new E;

	tab[0] = wzor.tab[0];
	tab[1] = wzor.tab[1];
	tab[2] = wzor.tab[2];

	agr1->set_b(wzor.agr1->get_b());
	agr2->set_c(wzor.agr2->get_c());
	agr3->set_d(wzor.agr3->get_d());
	agr4->set_e(wzor.agr4->get_e());
}
A &A::operator=(A &wzor)
{
if(&wzor == this) return *this;

delete agr1;
delete agr2;
delete agr3;
delete agr4;

	agr1 = new B;
	agr2 = new C;
	agr3 = new D;
	agr4 = new E;

	tab[0] = wzor.tab[0];
	tab[1] = wzor.tab[1];
	tab[2] = wzor.tab[2];

	agr1->set_b(wzor.agr1->get_b() );
	agr2->set_c(wzor.agr2->get_c() );
	agr3->set_d(wzor.agr3->get_d() );
	agr4->set_e(wzor.agr4->get_e() );

return *this;
}
A A::operator+(A p)
{
A out;

out.tab[0] = tab[0] + p.tab[0];
out.tab[1] = tab[1] + p.tab[1];
out.tab[2] = tab[2] + p.tab[2];

out.agr1->set_b( (agr1->get_b() + p.agr1->get_b() ) );
out.agr2->set_c( (agr2->get_c() + p.agr2->get_c() ) );
out.agr3->set_d( (agr3->get_d() + p.agr3->get_d() ) );
out.agr4->set_e( (agr4->get_e() + p.agr4->get_e() ) );

return out;
}

void F::przypisz(B p)
{
	cout << "F wynosi = " << f << endl;
	f = p.b;
	cout << "Teraz f wynosi = " << f << endl;
}
///////// plik main.cpp /////////////////////////////
#include<iostream>
using namespace std;

#include"klasa.h"

ostream &operator<<(ostream &stream, A &p)
{
	stream << p.tab[0] << " " << p.tab[1] << " " << p.tab[2] << endl;
	stream << p.agr1->get_b() << " " << p.agr2->get_c() << " " << p.agr3->get_d() << " " << p.agr4->get_e() << endl;

return stream;
}
istream &operator>>(istream &stream, A &p)
{
int tmp;
cout << "Podaj tab[0] = ";
stream >> p.tab[0];
cout << "Podaj tab[1] = ";
stream >> p.tab[1];
cout << "Podaj tab[2] = ";
stream >> p.tab[2];

cout << "Podaj agr1->b = ";
stream >> tmp;
p.agr1->set_b(tmp);
cout << "Podaj agr2->c = ";
stream >> tmp;
p.agr2->set_c(tmp);
cout << "Podaj agr3->d = ";
stream >> tmp;
p.agr3->set_d(tmp);
cout << "Podaj agr4->e = ";
stream >> tmp;
p.agr4->set_e(tmp);

return stream;
}
A operator-(A a, A b)
{
A out;

out.tab[0] = a.tab[0] - b.tab[0];
out.tab[1] = a.tab[1] - b.tab[1];
out.tab[2] = a.tab[2] - b.tab[2];

out.agr1->set_b( (a.agr1->get_b() - b.agr1->get_b() ) );
out.agr2->set_c( (a.agr2->get_c() - b.agr2->get_c() ) );
out.agr3->set_d( (a.agr3->get_d() - b.agr3->get_d() ) );
out.agr4->set_e( (a.agr4->get_e() - b.agr4->get_e() ) );

return out;
}



int main()
{
A *A1;
A1 = new A;


delete A1;

system("pause");
return 0;
}

W main nic nie robię bo samo stworzenie obiektu jest problemem.
Proszę o pomoc oraz proszę o wszelkie uwagi do całości programu.

Z góry dziękuje.

Kod w załącznikach.

0

Problem jest dość prosty, ale na pierwszy rzut oka można go tak łatwo nie zauważyć.
W konstruktorze A tworzysz obiekty typu B, C, D, E. I teraz skoro te obiekty dziedziczą bezpośrednio lub pośrednio A to w momencie ich konstruowania jest uruchamiany konstruktor z A(wg. zasady najpierw konstruktory klas podstawowych, potem własny). Skoro znowu jest odpalany konstruktor A to znowu są tworzone obiekty B, C, D, E, więc znowu odpalany jest konstruktor A ... i tak do znudzenia - tzn. do zapchania stosu lub co mało prawdopodobne wyczerpania pamięci(ram + swap).

Konkluzja: nie możesz tworzyć tych obiektów w konstruktorze.

0

Można by było stworzyć konstruktor z argumentem i wrzucić go do listy inicjalizacyjnej konstruktora klasy B, wtedy przy dziedziczeniu byłby uruchamiany ten konstruktor z argumentem w którym nie ma tej alokacji na obiekty klas B,C,D,E. Problem znowu się pojawi w momencie gdy do pracy wejdzie destruktor klasy A i będzie chciał usunąć coś czego nie ma.

Z tego wynika wg. mnie, że powinienem stworzyć dwie funkcje: jedna która alokuje, a druga która usuwa pamięć dla tych obiektów agregowanych klas B,C,D,E.
Trochę jak gdyby konstruktor i destruktor powinien to robić, ale widać ze w tym programie niemożna tego zastosować.

0

Problem z destruktorem możesz rozwiązać w ten sposób:

  1. w konstruktorze przypisujesz tym wskaźnikom wartość NULL
  2. w destruktorze wywołujesz delete tylko dla wskaźników, które nie pokazują na NULL

Ogólnie taka hierarchia dziedziczenia jest po prostu totalnie bez sensu i zupełnie nie rozumiem sensu tego zadania... No ale na wykładowce nie ma rady ;)

0

Racja ;) dzięki piękne wszystko działa prawidłowo ;) dziękuje za poświęcony czas.

Chciałbym jeszcze się upewnić czy asocjacja w moim zadaniu jest poprawnie zrobiona.

class G
{
private:
        C *m_C;
public:
        void Ustaw_Relacje(C *p_C) { m_C = p_C; }
};

O to ta część kodu powyżej.

Czy powinienem zarezerwować pamięć, bo nie wiem czy dobrze to rozumiem.
wg. mnie rezerwuje się pamięć na obiekty agregowane, a jeśli chodzi o asocjacie to ona ma tylko wskazywać na coś w tym przypadku na obiekt klasy C.

uhm... urodził mi się kolejny problem.

int main()
{
B B5;
F F5;

F5.przypisz(B5);

system("pause");
return 0;
}

Chcę pokazać, że przyjaźń działa prawidłowo, podczas kompilowania - kompilator przerywa pracę i wskazuje na funkcje "int get_b() { return b; }
Nawet jeśli dam w tej funkcji przypisz() tylko cout << to jest błąd ;/
Hm w sumie jak funkcja przypisz() - przyjmie jako argument obiekt klasy B przez referencje to nie ma problemu. Problem się pojawia w momencie tworzenia tymczasowej kopii.

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