Dziedziczenie i includy

Dziedziczenie i includy
Wronq
  • Rejestracja: dni
  • Ostatnio: dni
0

Witam!

Tworzę aktualnie projekt, w którym chcę mieć zorganizowanie, zhierarchizowane GUI, podobnie jak wygląda to w C#. Więc zabrałem się do roboty i na początek stworzyłem klasę CControl (która w moim przypadku jest abstrakcyjna, ale o tym zaraz...), która zapewnia obsługę zdarzeń, pozycję itp. Potem stworzyłem klasę/kontrolkę CPanel, która jest niejako prototypem dla klas zawierających w sobie kolejne kontrolki. Potem stworzyłem sobie klasę CButton dziedziczącą po CControl (ponieważ button nie potrzebuje mieć kontrolek-dzieci) i działa ona tak jak powinna. Następnym krokiem było stworzenie jakiegoś pojemnika na kontrolki, stworzyłem więc klasę CContainer dziedziczącą po CPanel. I tu zaczynają się schody ponieważ CPanel zawiera vector CContainerów, aby móc po nich iterować i wywoływać ich zdarzenia. Więc sytuacja w kodzie wygląda tak:

ClassContainer.h

Kopiuj
#ifndef DEF_CONTAINER
#define DEF_CONTAINER

#include "main.h"
#include "ClassTitleBox.h"

using std::vector;

class CContainer : public CPanel
{
    public:
    CContainer();
    void initialize(int id, char* name, int x, int y , int sizeX, int sizeY, char* titleText, int hidable, int minizable);
    void remove();
    void Draw();

    int onMouseDown(int x, int y);
    int onMouseUp(int x, int y);
    int onMouseMove(int x, int y);
    int onKeyDown(int Key);

    void Minimize(int mode);
    void Hide(int mode);

    void setFollowMouse(int mode);
    void setRelativeMousePos(int x, int y);
    void setTitleText(char* textString);

    int getActualSizeX();
    int getActualSizeY();
    private:
};

#endif

ClassPanel.h

Kopiuj
#ifndef PANEL_H
#define PANEL_H

#include "main.h"

#include "ClassControl.h"
#include "ClassButton.h"
#include "ClassContainer.h"

using std::vector;

class CPanel : public CControl
{
    public:
        CPanel();

        vector<CButton> Buttons;
        void AddButton(CButton Btn);

        vector<CContainer> Containers;
        void AddContainer(CContainer Cnt);

        virtual void Draw();

        virtual int onMouseDown(int x, int y);
        virtual int onMouseUp(int x, int y);
        virtual int onMouseMove(int x, int y);
        virtual int onKeyDown(int Key);

    protected:
        void DrawChildren();
        int ProcessMouseDown(int x, int y);
        int ProcessMouseUp(int x, int y);
        int ProcessMouseMove(int x, int y);
        int ProcessKeyDown(int Key);

    private:
};

#endif // PANEL_H

W main.h znajdują się jakieś funkcje globalne i includy windows.h, vector.h itd. Nazwy metod i parametry jakie przyjmują nie są ważne :)
Gdy próbuję to skompilować kompilator krzyczy, że expected class-name before '{' token przy okazji podświetlając pierwszy nawias { deklaracji klasy CContainer. No i jest to dość logiczne, ponieważ CContainer nie ma pojęcia o istnieniu klasy CPanel. Spróbowałem dodać w pliku ClassContainer.h #include "ClassPanel.h", lecz znowu ten sam błąd, ponieważ plik ClassPanel.h jest obdarzony jest zabezpieczeniem w postaci #ifndef. Dodałem więc deklarację klasy class CPanel; najpierw w pliku ClassPanel.h jeszcze przed includami, a potem w ClassContainer.h po includach - błąd w obu przypadkach był ten sam, mianowicie forward declaration of struct CPanel'// na deklaracji klasy i //invalid use of undefined type struct CPanel' przy //class CContainer : public CPanel. Trochę mnie dziwi słówko struct w tym błędzie... Moje pytanie brzmi w jaki sposób mam napisać includy/deklaracje czy coś innego, aby poprawnie mi się wszystko skompilowało i działało jak należy?
Na początku napisałem o klasie CControl. Deklaruje ona metodę Draw, która odświeża/rysuję kontrolkę i eventy myszki. Aby ułatwić sobie pracę chciałem zrzutować inne kontrolki do ich klasy bazowej (oczywiście wtedy CControl nie może i nie była abstrakcyjna) i wywołać tą metodę Draw, lecz niestety nie udało się tak zrobić i muszę dla każdego elementu osobno iterować, tworzyć nowy vector i metody dodające/usuwające kontrolki. Da się zrobić tak, żeby wywołać metody Draw klas pochodnych w jednej iteracji? Czyli zamiast:

Kopiuj
vector<CButton>::reverse_iterator btnIT;
for(btnIT = Buttons.rbegin(); btnIT != Buttons.rend(); ++btnIT)
{
    btnIT->onMouseDown(x, y);
}

vector<CContainer>::reverse_iterator cntIT;
for(cntIT = Containers.rbegin(); cntIT != Containers.rend(); ++cntIT)
{
    cntIT->onMouseDown(x, y);
}

//i dla każdego kolejnego typu kontrolek to samo, a jest/będzie ich sporo...

zrobić tak:

Kopiuj
vector<CControl>::reverse_iterator ctrlIT;
for(ctrIT = Controls.rbegin(); ctrlIT != Controls.rend(); ++ctrlIT)
{
    ctrlIT->onMouseDown(x, y);
}

Jeszcze pytanie numer 3. Czy idę w dobrą stronę ku zorganizowaniu GUI? Czy są na to jakieś inne sposoby?

Przydługawy post mi wyszedł, ale liczę na waszą pomoc! :D
Przy okazji dodam, że jako IDE używam Code::Blocks.

Pozdrawiam, Wronq!

Shalom
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Space: the final frontier
  • Postów: 26433
0

Za duzo tekstu, za malo konkretów :P
Jesli chodzi o includy:
Jeśli używasz <vector> to go includuj. Nie zakładaj że "inny nagłówek go includuje" tylko go includuj. Tak samo ze wszystkimi innymi klasami. Jedyny wyjątek mogą stanowić klasy z krzyżowymi zależnościami, wtedy musisz wykorzystać deklaracje zapowiadające. Jeśli chodzi o błąd "forward declaration of struct X" to słowo struct moze tutaj oznaczać zarówno klasę jak i strukturę, bo w C++ jedyna róznica miedzy klasą i strukturą jest taka że dla klasy domyślny kwalifikator dostępu do private a dla struktury to public.

Wronq
  • Rejestracja: dni
  • Ostatnio: dni
0

Starałem problem się opisać. Konkretnie, hm...
Klasa A dziedziczy z klasy B , klasa B zawiera referencję klasy A (właściwie ich vector, jeśli to robi jakąś różnicę). Co ma co includować i gdzie i czego deklaracja ma się znaleźć?

Shalom
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Space: the final frontier
  • Postów: 26433
0

Ok, ma to wyglądać tak:
http://student.agh.edu.pl/~pstanisl/src/

Xupicor
  • Rejestracja: dni
  • Ostatnio: dni
0

Przykład dobry, tylko odradzałbym używania using namespace std; globalnie w nagłówku. ;)

Shalom
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Space: the final frontier
  • Postów: 26433
0

Oczywiście, tak sobie to z przyzwyczajenia napisalem, ale oczywiście jeśli ktos korzysta z własnych namespaców i nie jest pewien czy stosowane przez niego nazwy nie zazębiają się z std:: to warto wybierać co dokładnie z std nas interesuje :)

Wronq
  • Rejestracja: dni
  • Ostatnio: dni
0

Ok. Jakoś to ruszyłem, w delikatnie inny sposób, pewnie troszkę dziwaczny, ale działa. Wielkie dzięki za kod, pomógł mi i za szybkie odpowiedzi.
Nie wiem, czy wypada pytać w tym temacie, ale jeżeli już opisałem problem...

  1. Klasa A posiada wirtualną metodę Wyswietl. Po klasie A dziedziczą klasy B, C i D. Każda implementuje na swój sposób metodę Wyświetl (np. wyskakuje MsgBox z nazwą danej klasy). W klasie E chciałbym mieć vector< A>1 do którego mógłbym dodawać referencje klas B, C i D i po którym mógłbym iterować wywołując metodę Wyświetl i wywoływana byłaby funkcja Wyświetl poszczególna dla klasy, na którą aktualnie wskazuje iterator. Nie jestem pewien, czy da się zrozumieć te wypociny, ale zapytam, czy jest coś takiego możliwe?
  2. Tego pytania niestety nie potrafię skonkretyzować. Brzmi ono, czy mój układ klas ułatwi mi współpracę z GUI, utrudni ją, czy może są na to jeszcze inne sposoby?

1Ta spacja tam się znajduje, ponieważ gdyby nie ona pojawiłby się w tym miejscu link.
Pozdrawiam, Wronq!

byku_guzio
  • Rejestracja: dni
  • Ostatnio: dni
0
  1. Jest to możliwe, ale musisz mieć vector< A&>. Wydaje mi się, że lepiej by było trzymać jednak wskaźniki vector< A*> - jak dla mnie jest to czytelniejsze ;)

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.