manipulacja wskaźnikami do składowych

0

Witam. Mam taki problem: chce napisać metodę/funkcję sortującą strukturę podobną do ks. telefonicznej. Chce to zrobić na zasadzie przekazania 3 parametrów: tablicy rekordów, porządku i klucza, tak by ta funkcja była jedna dla różnych typów klucza (np. char i int). Myślałem, aby przekazać klucz jako wskaźnik do składowej, ale musiałby być dowolnego typu. próbowałem void* ktel::, jednak nie mam zielonego pojęcia jak pobrać z tego jakieś dane (wkurza mnie operator .).

Drugą sprawą jest "arytmetyka" takich wskaźników. Czy można je jakoś zrzutować wartość na inny typ, dodawać, przesuwać na inne el. klasy. Taki hardcorowy przykład: pobrać wartość tego wskaźnika i dodawać do adr. jakiegoś obiektu i tak odczytywać wartości :-)

0

Coś mi się wydaje że chodzi Ci o szablony, rzuć okiem tutaj:
http://www.darkcult.republika.pl/kursy/kurs08.html

0
Halon napisał(a)

Drugą sprawą jest "arytmetyka" takich wskaźników. Czy można je jakoś zrzutować wartość na inny typ, dodawać, przesuwać na inne el. klasy. Taki hardcorowy przykład: pobrać wartość tego wskaźnika i dodawać do adr. jakiegoś obiektu i tak odczytywać wartości :-)

nie radze.. przyzwyczaj sie do operatorow ->* i .*, one wlasnie do takich rzeczy sluza. a nie radze, poniewaz obiekty czasem zawieraja pola o ktorych nie wiesz, np. _vptr w kalsach wirtualnych itepe

0

Nie chodzi mi o szablony. A klasa nie jest z żadnego szablonu, tylko własnej produkcji.
Zawiera:
3 int,
char[10],
1 bool,
5 tekst,
gdzie tekst to 1 int, void* db::* , a db składa sie z 5 void* i 5 char[20]

0

w kontekscie sortowania po roznych polach, wierz mi, chodzi o zastosowanie szablonu -- funkcji sortujacej:

#include <iostream>
#include <list>

struct element
{   bool flaga;
    std::string napis;
    int liczba;
    element(bool f, std::string const& n, int l):flaga(f),napis(n),liczba(l){}
};

void wypisz(std::list<element> const & t)
{   using namespace std;
    list<element>::const_iterator it=t.begin(), end=t.end();
    while(it!=end)
    {   cout << "F= " << it->flaga << " N='" << it->napis << "' L=" << it->liczba << endl;
        ++it;
    }
}

//sortowanie przez wstawianie, z pomoca listy pomocniczej, zeby bylo latwo przesledzic co sie dzieje
template<typename T>
void sort(std::list<element> & t, T element::* wskaznik)
{
    if(t.size() < 2) return;
    std::list<element> out;
    std::list<element>::iterator it, it_out;
    while(!t.empty())
    {
        it = t.begin();
        it_out = out.begin();
        while( it_out != out.end() )
            if( (*it).*wskaznik > (*it_out).*wskaznik )  //nie wazne na jaki typ "T" pokazuje wskaznik
                ++it_out;                         //wazne jedynie aby ten typ mial swoj operator >
            else
                break;
        //*przeniesienie* elementu IT z listy T, do listy OUT na pozycje IT_OUT
        out.splice(it_out, t, it);
    }
    //*przeniesienie* wszystkich elementow z OUT do T
    t.splice(t.end(), out);
}

int main()
{   using namespace std;

    list<element> tab;
    tab.push_back(element(false, "A", 4));
    tab.push_back(element(false, "D", 3));
    tab.push_back(element(true, "B", 2));
    tab.push_back(element(true, "C", 1));

    cout << "Po fladze: " << endl;
    sort(tab, &element::flaga);
    wypisz(tab);
    cout << endl;

    cout << "Po napisie: " << endl;
    sort(tab, &element::napis);
    wypisz(tab);
    cout << endl;

    cout << "Po liczbie: " << endl;
    sort(tab, &element::liczba);
    wypisz(tab);
    cout << endl;
}
-sh-3.00# g++ -Wall -ansi -pedantic x.cpp
-sh-3.00# ./a.out
Po fladze:
F= 0 N='D' L=3
F= 0 N='A' L=4
F= 1 N='C' L=1
F= 1 N='B' L=2

Po napisie:
F= 0 N='A' L=4
F= 1 N='B' L=2
F= 1 N='C' L=1
F= 0 N='D' L=3

Po liczbie:
F= 1 N='C' L=1
F= 1 N='B' L=2
F= 0 N='D' L=3
F= 0 N='A' L=4

0

Ale właśnie nie chce używać szablonu. Wiem, że to najwygodniejsze i najszybsze, a w dodatku pewnie mniej kodu do kompilacji. ale staram się zrobić to na wysyłanym wskaźniku dowolnego typu. Myślałem, żeby dodać tablice static int, które zawierałoby poszczególne offsety pól w klasie i wysyłać odpowiednie do funkcji, ale mogą być trudności w sortowaniu int`ów 4 bajtowych (robić po bajcie najprawdopodobniej).

0

w poscie powyzej dostawilem kod ktory wlasnie napisalem, niestety jak widze nie wyrobilem z napisaniem go przed Twoim postem... w/w kod uzywa wskaznikow-na-pole-po-ktorym-chce-sortowac i problem TYPU WSKAZNIKA jest wlasnie rozwiazany poprzez szablon!!

0

Uparty jestem i spróbuje jeszcze zrobić na void* , a jak nie pójdzie to zostanę przy szablonie i ulubionym bąbelku :)
Dzięki

0

A może o to ci chodzi?:

typedef bool (*TPorownanie)(TTwojRekord & a, TTwojRekord & b);
typedef vector<TTwojRekord> TTwojaTablica; // nie wiem jak ty zdefiniowałeś tablicę

void TwojeSortowanie(TTwojaTablica & tab, TPorownanie fun)
{
       int i,j;
       int n<tab.size();

       for(i=0;i<n-1;i++)
           for(j=i+1;j<n;j++)
               if((*fun)(tab[i],tab[j]))
                    swap(tab[i],tab[j]);
}

A potem wywołując zmieniasz sposób sortowania przez podanie funkcji porównującej. (zero szablonów)

0

nie, chodzilo o cos takiego jak ja podalem, gdzie do sortera podajesz wskaznik na pole po ktorym ma pojsc sortowanie. tylko ze bez template'ow.. szczerze nie wiem jak autor wyobraza sobie odczytywac i porownywac zawartosc otypowana jako void*.. przeciez trzeba wiedziec NA CO ten wskaznik pokazuje, zeby wiedziec jaki jest SENS jego zawartosci i JAK je porownywac.. czy to sa double? inty? stringi? template w moim przyklazie jest dokladnie tylko po to, aby zachowac informacje o typie i automatycznie dobrac wlasciwy operator porownania..

0

innymi słowy robiąc na voidzie musisz "jakoś" zrobić to, co quetzalcoatl zrobił elegancko: oprócz samego adresu pola musisz mieć typ tego pola, a więc na przykład podawać dodatkowy enum:
enum TypPola { tpInt, tpString, tpFloat };
a następnie voidy na chama rzutować w switch/case, i dopiero po rzutowaniu porównywać wartości.
koszmar:

  1. obsługa tylko znanych, zapewne wbudowanych typów
  2. switch przy każdym porównaniu = zmuła
  3. podanie złego typu funkcji sortującej = niewidoczny błąd w runtime (dziwne wyniki i tylko tyle)
0
Ranides napisał(a)

elegancko

milutko, dziekuje :)

btw. wlasnie zaskoczylem, ze templacik wrecz powinnien wygladac:

template<typename U, typename T>
void sort(std::list<U> & t, T U::* wskaznik)

zeby nie uzalezniac od typu obiektu trzymanego w liscie.. ale juz nie bede poprawiac:)</u>

0

Ciekawy pomysł z tą funkcją porównującą, ale nie za bardzo rozumiem 1 typedef`a:

typedef bool (*TPorownanie)(TTwojRekord & a, TTwojRekord & b);

wygląda mi to na zdefiniowanie nakładki na bool, która jest wskaźnikiem do funkcji? Bardziej by mi to wyglądało na def. wskaźnika do funkcji zwracającej bool`a, a ten typedef po co?

Zrobiłem to na szablonach, jednak tak faktycznie to potrzebuje napisać operatory porównania a to jest równoznaczne z napisaniem funkcji porównujących (tyle samo roboty). Sposób MarkaR22 ma jeszcze jedną zaletę porównam w ten sposób napis z tablicy charów, natomiast dla szablonów nie za bardzo to wyjdzie.

A co do void* to pomysł wysypał się na ważności bajtów w napisie i liczbie.

0
typedef bool (*TPorownanie)(TTwojRekord & a, TTwojRekord & b);

czyta sie tak:

typedef -- ustaw alias
bool (*)(x, y) -- wskaznik na funkcje dwuargumentowa zwracajaca bool
TPorownanie -- nazwa aliasu

0

Nie bawiłem się wcześniej wsk. do funkcji na takim poziomie, a przemiły kompilator Dev zwraca mi cały czas blędy. Mam taki kod:

typedef bool (*porownanie)(rekord & a, rekord& b);

       bool fun1(rekord & a, rekord& b){ return (a.lp>b.lp);}
       bool fun2(rekord & a, rekord& b){return (a.tytul>b.tytul);}

porownanie fun[10];
fun[0] = fun1;
fun[1] = fun2;

i mi cały czas zwraca błędy, że
22 expected constructor, destructor, or type conversion before '=' token
22 expected ,' or ;' before '=' token
to samo linijkę niżej;

Nie mam pojęci już o co może chodzić, bo klasa rekord jest opakowana i każdy niestandardowy element ma swoje operatory przypisania i porównania nie mówiąc o konstr.

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