środa, 26 marca 2008

Wskaźniki na... "coś"

Zdarza się, że potrzebujemy w jednym obiekcie przechować dane więcej niż tylko jednego konkretnego typu. Np. chcielibyśmy otrzymać stos czy jakąś listę, na której znalazłyby się liczby zmiennoprzecinkowe, stałoprzecinkowe, łańcuchy znaków albo nawet obiekty dowolnej klasy. I co wtedy można zrobić? Teoretycznie można by wykorzystać unię - ale jest to dobre tylko dla niewielkich obiektów. Lepszym wyjściem byłoby użycie jakiegoś wskaźnika (przecież wskaźnik na dowolny typ na jednej platformie zajmuje zawsze tyle samo miejsca, dla 32-bit: 4B). No to świetnie, idea już jest, ale zaraz.. jak takie coś można właściwie zrobić? Jaki typ ma być tego wskaźnika?

Wskaźnik musi być zadeklarowany tak:
void* Wartosc;

No świetnie, ale jeszcze chyba jednego brakuje... przecież tak naprawdę nie wiemy, co (jaki typ) będzie wskazywane przez ten nasz nowy wskaźnik... może tam być dosłownie wszystko. Dlatego rozszerzymy sobie tą deklarację na klasę:

class TElement {
public:
void* Wartosc;
short int Typ;
};


Typ będzie nam potrzebny do tego, by potem uzyskiwać odpowiednie dane.
Na koniec musimy jeszcze oczywiście wprowadzić dane:

int* Calkowita;
double* ZmiennoPrzecinkowa;
TElement Tablica[2];

Calkowita = new int;
*Calkowita = 5;
Tablica[0].Wartosc = Calkowita;
Tablica[0].Typ = 1; // int
ZmiennoPrzecinkowa = new double;
*ZmiennoPrzecinkowa = 3.445;
Tablica[1].Wartosc = ZmiennoPrzecinkowa;
Tablica[1].Typ = 2; // double


Oczywiście, nie byłoby to nam do niczego potrzebne, gdybyśmy jeszcze nie wiedzieli, jak potem to wykorzystać. A i to wcale nie jest znowu takie trudne; ważne jest rzutowanie naszego wskaźnika na odpowiedni wskaźnik... Może przykład to rozjaśni:

switch (Tablica[0].Typ) {
case 1:
Calkowita = static_cast<int*> (Tablica[0].Wartosc);
cout << *Calkowita;
break;
case 2:
ZmiennoPrzecinkowa = static_cast<double*> (Tablica[0].Wartosc);
cout << *ZmiennoPrzecinkowa;
break;
}


Prawda, że proste?
Naturalnie, powyższą strukturę można wykorzystać dla dowolnych typów danych, włączając w to pojemniki STL'a, klasy, wskaźniki na obiekty, itd... Ile typów, tyle możliwości w skrócie.

1 komentarz:

Anonimowy pisze...

a co jak będzie lista kilkudziesięciu typów? Zastosujesz switch'a z 80 case'ami? ;)