Dziedziczenie, Asocjacja, Agregacja, Utility, Friend

Odpowiedz Nowy wątek
2011-09-05 19:02
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.

edytowany 5x, ostatnio: madmike, 2011-09-05 19:58
wrzuć kod w znaczniki <cpp></cpp> - byku_guzio 2011-09-05 19:10

Pozostało 580 znaków

2011-09-05 19:22
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.


Pozostało 580 znaków

2011-09-05 19:56
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ć.

edytowany 2x, ostatnio: Anander, 2011-09-05 20:07

Pozostało 580 znaków

2011-09-05 20:21
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 ;)


Pozostało 580 znaków

2011-09-05 20:34
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.

edytowany 6x, ostatnio: Anander, 2011-09-06 22:47

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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