Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++] Unia ze wskaźnikami, a dziedziczenie

Ostatnio zmodyfikowano 2013-02-04 15:32
Autor Wiadomość
gorylp
Temat założony przez niniejszego użytkownika
[C++] Unia ze wskaźnikami, a dziedziczenie
» 2013-02-03 21:46:55
Witam.
Nie znalazłem w internecie podobnego przykładu więc piszę tutaj.

Piszę symulator układów logicznych z pomocą Allegro5 w VC++ 2010 Express i w funkcji rysującej chciałbym wywołać funkcję rysującą każdej bramki logicznej z osobna a więc zrobiłem tak (w prawie pseudokodzie)
C/C++
class Element
{
protected:
    int x, y;
    bool state;
    /*mniej ważne elementy*/
public:
    virtual void draw() { }
    virtual void setInput( Element * ) { } //TEGO NIE MA W PRZYCISKU
    virtual void clearInput() { } //TEGO NIE MA W PRZYCISKU
    virtual void updateInput() { } //TEGO NIE MA W PRZYCISKU
    virtual void updateState() { } // TEGO NIE MA W KLASIE LAMPKA
    virtual void changeState() { } //TYLKO W KLASIE PRZYCISK
    bool getState() { return state; }
    /* mniej ważne elementy*/
};

class BramkaNOT
    : public Element
{
protected:
    /*mniej ważne elementy*/
    Element * input;
public:
    virtual void draw();
    /*mniej ważne elementy*/
};

void draw()
{
    rysuj( x, y );
}

int main()
{
    Element * element[ ILOSC_ELEMENTOW ];
    for( int i = 0; i < ILOSC_ELEMENTOW; ++i )
    {
        element[ i ] = NULL;
    }
   
    while( true )
    {
        if( klikniecieMysza && wybranyElement == NOT )
        {
            for( int i = 0; i < ILOSC_ELEMENTOW; ++i )
            {
                if( element[ i ] == NULL )
                {
                    element[ i ] = new BramkaNOT( myszX, myszY );
                }
                break;
            }
        }
        for( int i = 0; i < ILOSC_ELEMENTOW; ++i )
        {
            if( element[ i ] )
            {
                element[ i ]->draw();
            }
        }
    }

I jeśli nie tworzyłbym nadrzędnej klasy Element to musiałbym dla każdego obiektu tworzyć tablice i kombinacji w tym sporo by było. Ale tworząc klasę Element z tymi wszystkimi metodami wirtualnymi robię trochę bałaganu i często wywołuje puste funkcje (myślę że to spowalnia program).
Także pobierając dane z input-u muszę deklarować wskaźnik na obiekt typu element.

Jednakże tworząc po kilka różnych wskaźników (np. po 2 dla jednego rodzaju bramki) zajmę kupę pamięci przy 2000 bramek.

Więc kombinowałem i wpadłem na rozwiązanie:
C/C++
union Element
{
    BramkaNOT * NOT;
    BramkaAND * AND;
    /*itd.*/
}

Wówczas mogę tworzyć tablicę wskaźników której przyporządkuje dowolny obiekt, a zajmuje pamięci tyle co ilość wskaźników.

Te obiekty nie muszą być nawet powiązane ze sobą.

Ustaliłem że liczy się kolejność metod w klasie np.

C/C++
class BramkaNOT
{
protected:
    /*mniej ważne elementy*/
    bool state;
    Element * input;
public:
    void draw(); // 1 FUNKCJA
    void getState() { return state; } // 2 FUNKCJA
    /*mniej ważne elementy*/
};

class BramkaAND
{
protected:
    /*mniej ważne elementy*/
    bool state;
    Element * input1;
    Element * input2;
public:
    void getState() { return state; } // 1 FUNKCJA
    void draw(); // 2 FUNKCJA
    /*mniej ważne elementy*/
};

Element * element = new Element;
Element->NOT = new BramkaNOT;
Element->NOT->draw(); //WYWOŁA FUNKCJĘ draw() KLASY BramkaNOT
Element->AND->draw(); //WYWOŁA FUNKCJĘ getState() KLASY BramkaNOT -- TRZEBA ZMIENIĆ KOLEJNOŚĆ FUNKCJI W AND
Tutaj funkcję wywołuje już dowolnym typem wskaźnika

Czy takie rozwiązanie jest poprawne, czy pierwsze lepsze?

P.S. Uważam to na razie za ciekawostkę, ale może się jednak przydać
P.S.2 Niektóre bramki mogą dziedziczyć po np. bramka_dwuargumentowa itp. Rozważałem też klasy nadrzędne, Drawable itp.

EDIT:
Przy dziedziczeniu z klas typu Drawable, kolejność funkcji (w tym wypadku draw()) nie ma znaczenie, i nie w pływa na numery funkcji niedziedziczonych.
P-75677
Mrovqa
» 2013-02-03 21:59:57
Korzystaj z dziedziczenia. To drugie to modyfikacja zupełnie innej klasy (typu) - równie dobrze możesz sobie wsadzić wskaźnik na inta i nim operować.
Dlaczego drugi kod działa? Dane masz na tych samych offsetach, a metody zdefiniowane bezpośrednio w klasie są inline (choć to drugie ma mniejsze znaczenie, a w twoim przypadku chyba żadne). Możesz sobie wygenerować kod assembly i go przeanalizować, jeśli to Cię tak bardzo interesuje ;)
P-75682
gorylp
Temat założony przez niniejszego użytkownika
» 2013-02-03 22:12:41
Akurat dlaczego to działa to mniej więcej wiem.
O jakie chodzi tobie dziedziczenie, te z jednej klasy Element, czy z wielu różnych klas (Drawable itp.)?
Bo jeśli z jednej klasy Element, to jak mówiłem, jest dużo pustych funkcji, a z wielu różnych klas, to musiałbym tworzyć wskaźniki do każdego typu obiektu w każdym obiekcie (aby pobierać dane o stanie bramki), co zjadało by kupę pamięci.
A może znasz inne, bardziej sprytne rozwiązanie :).
P-75683
DejaVu
» 2013-02-03 22:40:01
Dziedziczenie + metody wirtualne. Nie martw się w tym wypadku o wywoływanie pustych metod, bo takich pustych metod możesz spokojnie wywołać z pół miliarda na sekundę. Pamięcią również bym się nie przejmował, bo 1000 bramek razy 100 bajtów to nadal daje zużycie pamięci poniżej 1MB.
P-75686
gorylp
Temat założony przez niniejszego użytkownika
» 2013-02-04 15:32:02
Dzięki wszystkim za odpowiedzi. Użyje dziedziczenia i zrobię pole zawierające typ klasy (enum ofc), i będę je sprawdzał switchem bo w sumie to w pętli logicznej 99% wywołanych funkcji ma swoją implementację.
P-75704
« 1 »
  Strona 1 z 1