Novo

Forum kao aplikacija na telefonu

Dodajte forum na početni ekran i koristite ga kao aplikaciju, sa menijem na dnu ekrana.

  • 15 odgovora
  • 6.112 pregleda

Najnovija ↓

Savet - inicijalizacija atributa 22.08.2009. u 15:04 · pre 209 meseci #1
Pozdrav,

interesuje me koji je najbolji nacin resiti sledeci problem.
Imam klasu sa npr 3 atributa, ime, prezime, jmbg. Imam XML datoteku ciji elementi se isto tako zovu.
<korisnik>
<ime> Korsink </ime>
<prezime> Prezime </prezime>
<jmbg> 1234434 </jmbg>
</korisnik>

Sad mi treba najlaksi nacin da inicijalizujem atribute klase...
Uvek mogu napraviti nesto tipa
if (element == "ime") objekat.ime = ime
else if....

Ali mislim da to nije pravo resenje.

Jel postoji u C++ mogucnost da kazem da atribut sa "imenom" dobije "vrednost"... Ili tako nekako.. ??
Re: Savet - inicijalizacija atributa 23.08.2009. u 19:46 · pre 209 meseci #3
Ne vredi razmišljati mnogo o takvim stvarima. Ako imaš tri članice klase, onda je if-else-if najefikasnije rešenje, pod uslovom da se to if-else-if ne ponavlja na deset mesta. Možeš eventualno umesto tri članice da koristiš map<string, string>, ali slutim da nema nikakve potrebe za tim. Kad bi bilo stotinak članica klase onda bi imalo smisla razmišljati o nekom elegantnijem rešenju.
Re: Savet - inicijalizacija atributa 24.08.2009. u 08:55 · pre 209 meseci #4
Citat:
Goran Arandjelovic: Je l' ti bilo kakvo menjanje izgenerisanih klasa odgovara ili njih nebi hteo da diraš?

Mogu da menjam klase.
Citat:
Mihajlo Cvetanović: ...Kad bi bilo stotinak članica klase onda bi imalo smisla razmišljati o nekom elegantnijem rešenju.

E bas o tome se radi :)

Znam da u C#-u i Javi postoji mogucnost dobijanja informacija o atributima, metodama i tako to, dalo bi se uraditi... Ali za C++ bas ne znam da li je to moguce i kako...
Re: Savet - inicijalizacija atributa 24.08.2009. u 11:29 · pre 209 meseci #5
Prvo što mi pada na pamet je da umesto 100 članica klase imaš jednu članicu koja je map<string, string>.

Druga opcija nije za ljude sa pejsmejkerom:

Code:

#include <map>
#include <string>
using namespace std;

class Klasa {
public:
  string jedan, dva, tri;
  static map<string, string Klasa::*> mapa;
}

map<string, string Klasa::*> Klasa::mapa;

main() {
  // mapa je staticka, ova inicijalizacija se radi samo jednom
  Klasa::mapa["jedan"] = &Klasa::jedan;
  Klasa::mapa["dva"]   = &Klasa::dva;
  Klasa::mapa["tri"]   = &Klasa::tri;

  Klasa objekat;
  objekat.*Klasa::mapa["jedan"] = "vrednost jedan";
  objekat.*Klasa::mapa["dva"] = "druga vrednost";
  objekat.*Klasa::mapa["tri"] = "nesto trece";
}
Re: Savet - inicijalizacija atributa 24.08.2009. u 18:27 · pre 209 meseci
izmenjeno 1 put, poslednji put Goran Arandjelovic 24.08.2009. u 19:12
  1. Goran Arandjelovic24.08.2009. u 19:12zapis iz teksta poruke
#6
@Mihajlo
S tim sto nigde nije pomenuo da su svi atributi istog tipa, vec verovatno i ne moraju da budu.

--

Evo jedne ideje:

Code:

#include <string>
#include <iostream>
using namespace std;

class izgenerisana_klasa
{
  public:
    /* konstruktori/destruktor i ostale metode */
    template<typename T>
    void set_attr(string attr_name, T value)
    {
      if(attr_name == "jedan"){
        jedan = value;
      }else if(attr_name == "dva"){
        dva = value;
      }else if(attr_name == "tri"){
        tri = value;
      }else if(attr_name == "cetiri"){
        cetiri = value;
      }
    }
  private:
    int jedan;
    string dva;
    float tri;
    int cetiri;
};

int main()
{
  izgenerisana_klasa Test; // ako postoji default konstruktor
  
  Test.set_attr("jedan", 5);
  Test.set_attr("dva", "neka vrednost");
  Test.set_attr("cetiri, 15);
  Test.set_attr("tri", 5.14); // mada bi mogao da prodje i int

  // ili... umesto if(element == "ime")...

  Test.set_attr(element, val); // gde je val vrednost koja odgovara tom elementu

  return(0);
}


Ovo gore nisam testirao, ali bi trebalo da je ok. Naravno, imam i neku ideju za mnogo krace resenje (koje cak verovatno nebi ni zahtevalo izmenu generisanih klasa, ali je malo bolesno...)

Edit: @Mihajlo, na koju si drugu opciju mislio ako nije tajna?
Re: Savet - inicijalizacija atributa 25.08.2009. u 10:25 · pre 209 meseci #7
Ni ja nisam testirao, ali cenim da ovo ne može da se kompajlira. Ako instanciraš set_attr sa T kao int onda će ti kompajler javiti grešku u liniji "dva = value;" da nema operator= koji prima int. Ako instanciraš sa T kao string onda je greška u liniji "jedan = value;" jer kompajler ne zna kako da konvertuje string u int.
Re: Savet - inicijalizacija atributa 25.08.2009. u 12:59 · pre 209 meseci #8
Kombinuj explicitnu specijalizaciju sa resenjem koje je dao Mihajlo Cvetanović.
Potpis
AKA DDMM
Re: Savet - inicijalizacija atributa 25.08.2009. u 16:34 · pre 209 meseci #9
@Mihajlo
Da, dobro si primetio. Greška. Ali evo sada TESTIRANOG rešenja koje koristi nešto slično statičkom IF-u:

Code:

#include <string>
#include <iostream>
using namespace std;

template<typename T, typename U>
struct SET_F
{
  static void set(T &arg1, U &arg2)
  {
  }
};

template<typename T>
struct SET_F<T, T>
{
  static void set(T &arg1, T &arg2)
  {
    arg1 = arg2;
  }
};

struct SET
{
  template<typename T, typename U>
  SET(T &attr, U &value)
  {
       SET_F<T, U>::set(attr, value);
  }
};

class izgenerisana_klasa
{
  public:
    /* konstruktori/destruktor i ostale metode */
    template<typename T>
    void set_attr(string attr_name, T value)
    {
      if(attr_name == "jedan"){
        SET i(jedan, value);
      }else if(attr_name == "dva"){
        SET i(dva, value);
      }else if(attr_name == "tri"){
        SET i(tri, value);
      }else if(attr_name == "cetiri"){
        SET i(cetiri, value);
      }
    }
  
  private:
    int jedan;
    string dva;
    float tri;
    int cetiri;
};

int main()
{
  izgenerisana_klasa Test; // ako postoji default konstruktor
  
  Test.set_attr("jedan", 5);
  Test.set_attr("dva", string("neka vrednost"));
  Test.set_attr("cetiri", 15);
  Test.set_attr("tri", 5.14f);

  // ili... umesto if(element == "ime")...

  // Test.set_attr(element, val); // gde je val vrednost koja odgovara tom elementu

  return(0);
}


Naravno, moguće je dodati potrebne specijalizacije da se dopusti float -> double, const char* -> string i slične stvari. Ovo radi za identične tipove.
Re: Savet - inicijalizacija atributa 25.08.2009. u 16:55 · pre 209 meseci #10
Mislim da je kod malo neefikasan, jer imaš template funkciju set_attr koja će se instancirati onoliko puta koliko ima različitih tipova, ali u svakoj of tih funkcija ispitivaće se i oni attr_name koji nisu datog tipa. Drugi detalj je što mi se čini da su input vrednosti za naš algoritam uvek stringovi, a algoritam je taj koji treba da uradi konverziju u odgovarajući tip na osnovu imena atributa. A možda ne treba da komplikujemo, možda je string jedini tip. Početni poster treba da kaže šta mu treba.

Nego da se vratimo početnom problemu. Šta ako imaš stotinu (ili hiljadu) atributa, a ne samo četiri? Da li i onda da koristimo if-else-if kobasicu?
Re: Savet - inicijalizacija atributa 25.08.2009. u 18:41 · pre 209 meseci #11
To što ima nepotrebnih ispitivanja, to bi moglo da se reši bez problema. Ako su input-i isključivo stringovi, onda ja nisam dobro razumeo, mislio sam da je input uređeni par (string ime, T vrednost), gde je T baš odgovarajući tip, a ne string.

Ali u pravu si, neka čovek kaže tačno kakav mu je input, nije baš bio najprecizniji tako da sam ja obradio generalan slučaj.
Re: Savet - inicijalizacija atributa 26.08.2009. u 01:41 · pre 209 meseci
izmenjeno 1 put, poslednji put Eurora3D Team 26.08.2009. u 01:52
  1. Eurora3D Team26.08.2009. u 01:52zapis iz teksta poruke
#12
Mozes ovako nesto ...
Broj podataka nije ogranicen ali jeste vrsta ... ali to moze lako da se prevazidje dodavajem funkcija itd.
Podatci se inicijalizuju prvim upisom,
Nisam mnogo razradjivao ali bi trebalo da je to to sto si trazio.
Code:

//
#include <iostream>
#include <string>
#include <vector>
using namespace std;

//prouci i
//#include <typeinfo>
// cout << "a is: " << typeid(a).name() << '\n';

//prva klasa
class DataClass
{
public:
    string value_name;

    DataClass():type(0){}
    inline bool SetValue(string s_value_name, int value){if(!type) {type = 1; value_name = s_value_name;} if(type == 1) {Int = value;return true;} return false;}
    inline bool SetValue(string s_value_name, float value){if(!type) {type = 2; value_name = s_value_name;} if(type == 2) {Float = value; return true;} return false;}
    inline bool SetValue(string s_value_name, string value){if(!type){type = 3; value_name = s_value_name;} if(type == 3) {String = value;return true;} return false;}
    inline bool GetValue(string s_value_name,int& i){if(type == 1) {i = Int;return true;} return false;}
    inline bool GetValue(string s_value_name,float& f){if(type == 2) {f = Float;return true;} return false;}
    inline bool GetValue(string s_value_name,string& s){if(type == 3) {s = String;return true;} return false;}

private:
    int type;
    int Int;
    float Float;
    string String;
};

typedef vector<DataClass*> DC; // definisanje vektora tipa DataClass

//druga klasa
class DataContainer
{
public:
    //set
    void SetValue(string value_name, int value)
    {
        bool n = false;
        DataClass* dc = GetData(value_name);
        if(!dc)
        {
            dc = new DataClass();
            n = true;
        }
        if(!dc)
            return;
        if(n && dc->SetValue(value_name,value))
            data_list.push_back(dc);
    }
    void SetValue(string value_name, float value)
    {
        bool n = false;
        DataClass* dc = GetData(value_name);
        if(!dc)
        {
            dc = new DataClass();
            n = true;
        }
        if(!dc)
            return;
        if(n && dc->SetValue(value_name,value))
            data_list.push_back(dc);
    }
    void SetValue(string value_name, string value)
    {
        bool n = false;
        DataClass* dc = GetData(value_name);
        if(!dc)
        {
            dc = new DataClass();
            n = true;
        }
        if(!dc)
            return;
        if(n && dc->SetValue(value_name,value))
            data_list.push_back(dc);
    }
    //get
    bool GetValue(string value_name, int& value)
    {
        DataClass* dc = GetData(value_name);
        if(!dc)
            return false;
        return dc->GetValue(value_name,value);
    }
    bool GetValue(string value_name, float& value)
    {
        DataClass* dc = GetData(value_name);
        if(!dc)
            return false;
        return dc->GetValue(value_name,value);
    }
    bool GetValue(string value_name, string& value)
    {
        DataClass* dc = GetData(value_name);
        if(!dc)
            return false;
        return dc->GetValue(value_name,value);
    }
    
private:
    DataClass* GetData(string value_name)
    {
        
        if(!data_list.empty())
        {
            DataClass* dc = 0;
            DC::iterator Iterator;
            for (Iterator = data_list.begin(); Iterator != data_list.end();Iterator++)
            {
                dc = *Iterator;
                if(dc->value_name == value_name)
                    return dc;
            }
        }
        return (DataClass*) 0;
    }

    DC data_list; // vektor tipa DataClass
};

DataContainer Memory;

int main () 
{
    int i1,i2;
    Memory.SetValue("int_jedan", 1);
    Memory.SetValue("int_dva", 2);

    Memory.GetValue("int_dva", i2);
    Memory.GetValue("int_jedan", i1);

    float f1=1.0f, f2=2.0f;

    Memory.SetValue("float_jedan", f1);
    Memory.SetValue("float_dva", f2);

    //zamenili smo mesta
    Memory.GetValue("float_jedan", f2);
    Memory.GetValue("float_dva", f1);

    string s1, s2 = "s2 string";

    Memory.SetValue("string_jedan", s2);
    Memory.SetValue("string_dva", "s1 string");

    Memory.GetValue("string_jedan", s2);
    Memory.GetValue("string_dva", s1);

    cout << "int_jedan " << i1 << endl;
    cout << "int_dva " << i2 << endl;

    cout << "float_jedan " << f1 << endl;
    cout << "float_dva " << f2 << endl;

    cout << "string_jedan " << s1 << endl;
    cout << "string_dva " << s2 << endl;
    
    return 0;
}
Potpis
HomePage http://www.eurora3d.com
Re: Savet - inicijalizacija atributa 26.08.2009. u 10:53 · pre 209 meseci #13
Ovde bi mogao da se ubaci i jedan union, greota da se rasipa memorija. Uzgred, if-else-if (teoretsku) kobasicu i direktan pristup članicama klase si zamenio iteracijom liste u for-if petlji. Taj deo koda je sad manji, ali je neefikasniji i što se tiče upisa i što se tiče čitanja. Kod upisa moramo da prođemo kroz celu listu da bismo shvatili da dati atribut ne postoji. Kod čitanja nemamo više direktan pristup nego opet moramo da iteriramo po listi.
Re: Savet - inicijalizacija atributa 26.08.2009. u 13:43 · pre 209 meseci
izmenjeno 1 put, poslednji put Eurora3D Team 26.08.2009. u 14:24
  1. Eurora3D Team26.08.2009. u 14:24zapis iz teksta poruke
#14
Da greota :) (ti si iz c++ kao i ja, ovi iz NETa bacaju MB a ne bytove) , ali koliko sam shvatio najvise ce da koristi string tako da se rasipa ~ (sizeof(int) + sizeof(float)) * broj podataka ...
A i nije neki sampion u brzini ... to mi je prvo palo na pamet.
U svakom slucaju resenje je fleksibilno i moze lako da ga sredi i neko ko nema mnogo iskustva , tako da kome treba eto mu neki pocetak
...
Da najvaznije
U ovu klasu moze da se lako ubaci 1000 raznih podataka na jednostavan nacin ... normalno mogu i da se procitaju
Potpis
HomePage http://www.eurora3d.com
Re: Savet - inicijalizacija atributa 26.08.2009. u 18:48 · pre 209 meseci #15
Da dodam , ovim nacinima kako ste vi probali nije moguce u klasu dodati hiljede atibuta kojima unapred ne znamo imena ... tako da je ovo trece resenje jedino koje moze da resi ovaj problem. Ja sam ogranicio ono sto znamo , tipove podataka.
Ako neko ima bolju ideju neka napise ... poz
Potpis
HomePage http://www.eurora3d.com
Prijavite se da biste odgovorili u ovoj temi.PrijavaRegistracija

Premeštanje teme