RTTI, dynamic_cast i klasy abstrakcji

0

Witam!

Obecnie pisze klasę do obsługi drzew binarnych z tym że węzły są zupełnie inne niż liście. W tym celu użyłem RTTI i teraz mam klasę bazową BASE_NODE, i dwie klasy dziedziczące po niej tzn NODE oraz LEAF. W drzewie przechowuje wskaźniki typu BASE_NODE i rzutuje je za pomocą dynamic_cast odpowiednio na wskaźnik LEAF i wskaźnik NODE zależnie od tego na co wskazują.
Wszystko działa ładnie jak na razie ale aby można było korzystać z dynamic_cast muszę mieć przynajmniej jedną funkcje wirtualną, czy da sie to jakoś obejść i jeśli tak to jak? Nie chce mieć pustej funkcji w każdej z tych klas. I przy okazji czy jest to dobry sposób rozwiązania tego problemu czy znacie lepsze?

0

zeby RTTI dzialalo, obiekt musi miec vtable i kropka. stad wymog aby byla jakas metoda wirtualna. jesli masz wspolna baze - BASE_NODE - umiesc w niej jakakolwiek durna metode wirtualna, moze byc nawet niepotrzebna - zostanie ona odziedziczona przez wzystkie pochodne i wszystkie pochodne z automatu beda mialy vtable. np. destruktor:

class BASE_NODE
{public:
    virtual ~BASE_NODE() {..a tutaj kod destruktora lub pustka..}
};

class NODE: public BASE_NODE  //z automatu ~NODE jest wirtualne, wiec jest vtable, wiec NODE jest  RTTI-ok
{
};

hm.. lepsze..? ogolnie z RTTI chyba przekombinowales.. po co rozszcepiac node'y na dwie klasy? chyba ze to ma jakis wyzszy sens.. IMHO, jedna klasa NODE calkowicie wystarczy takze do zaimplementowania liscia.

Tradycyjnie na chlopaski rozum: w NODE umieszczasz trzy wskanziki/wartosci: lewe, prawe, wartosc. Jak to jest node, to wartosc jest pusta, ale wskazniki na dzieci - ustawione. Jak to jest lisc - wartosc jest niepusta a wskazniki sa nullami. Mozna sie sprzeczac czy to bedzie wydajniejsze pamieciowo niz RTTI.

Wiec, mozna zajetosc pamieci zmniejszyc o 1/3: biorac pod uwage ze w drzewie binarnym dla kazdego wezla zachodzi ze albo LEWE==PRAWE==NULL i jest to lisc, albo LEWE!=PRAWE i jest to wezel.. to mozna zauwazyc ze tak na prawde warunkiem liscia mozna uczynic LEWE==PRAWE i zrobic taki trick:

struct Wartosc; //costam, nieistotne co

class Node
{
    union {Node* lewy; Wartosc* w1; };   //to zajmuje miejsce jednego wskaznika
    union {Node* prawy; Wartosc* w2; }; //i to rowniez

public:
    Node(Wartosc* ptr) :  //inicjalizujac jako LEAF, upewniamy sie ze L i R sa ROWNE
        w1(ptr),
        w2(ptr)
    {   ;
    }

    Node(Node* left, Node* right) :  //inicjalizujac jako NODE - wrecz przeciwnie
        lewy(left),
        prawy(right)
    {   if(lewy==prawy) throw logic_error("dzieci musza byc rozne");
    }

    bool IsLeaf()  //teraz, uzywajac tych zalozen..
    {   return lewy == prawy;    //nie wazne czy sa rowne NULL czy COS, wazne ze rowne
    }

    Wartosc* getValue()
    {   if(!IsLeaf())throw logic_error("to nie lisc!");
        return w1;  //nie wazne czy w1 czy w2 - przeciez sa rowne
    }

    void setValue(Wartosc* ptr)
    {   if(!IsLeaf())throw logic_error("to nie lisc!");
        w1=w2=ptr;
    }
}

w ten sposob mamy jedynie NODE'y i nauczylismy NODE'y trzymac wartosci ...bez straty miejsca na trzeci wskaznik.

zmiast unionow mozna by sobie castowac static_castem z NODE* na WARTOSC*, ale uniony chyba jednak ladniejsze.. i oczywiscie typ WARTOSC jest nie istotny, wazne zeby to byl wskaznik, albo cos niewiekszego niz sizeof(void*)

0

Myślałem o czymś podobnym ale jednak wole RTTI, w node potrzebuje tylko płaszczyznę a w liściu mam sporo extra informacji jak np spis ścian, twój sposób wymusza jeszcze dodatkowe adresowanie przez wskaźnik, a tego wole uniknąć dla wygodny, po prostu jest dużo adresowań typu, najpierw z liścia do listy ścian, z listy ścian do listy wierzchołków itp. wiec nie chce kolejnego zagnieżdżania i zyskać większą czytelność kodu, poza tym wygenerowane drzewo będzie podawane do kolejnych algorytmów.

Z resztą to jest tylko kompilator map, wykonuje sie tylko raz dla każdej mapy wiec oszczędność pamięci nie jest priorytetem.

W każdym razie dzięki za pomoc [browar]

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