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

Klasy - dostęp do zmiennych (i ich typów) wewnątrz klasy bez ich nazwy

Ostatnio zmodyfikowano 2013-10-11 19:52
Autor Wiadomość
berkov
Temat założony przez niniejszego użytkownika
Klasy - dostęp do zmiennych (i ich typów) wewnątrz klasy bez ich nazwy
» 2013-10-08 18:03:23
Hey ho!

czy istnieje jakis sposob ( i juz cos mi mowi ze nie :-) ) dostepu do zmiennych (oczywiscie public) w klasie bez znajomosci ich nazw? Chodzi o to by wyrzucic wszystkie po koleji lacznie z ich typami.

Przyklad:
Program zapisuje do bazy danych (ADO - SQL) roznego typu dane, insert oraz update. Dane te pochodza z roznych klas, np:
 
C/C++
class FVT
{
public:
    long lp;
    _bstr_t nazwa;
    double ilosc;
    _bstr_t jm;
    double cena;
    _bstr_t vat;
    double netto;
    double brutto;
   
};


chcialbym uzywac jednej funkcji, ktorej powiem, czy to insert czy update, na jakiej bazie, jaka tabelka, jaki rekord (dla update) i podam swoja klase w ktorej przechowuje zmienne, funkcja ta przeleci przez cala klase (ale po koleji) i automatycznie rozpozna typ(mozliwe tylko, long, _bstr_t, double) i wpisze wartosci do danej tabelki...  cos a'la:
C/C++
bool db_write( bool insertORupdate, _bstr_t bazadanych, _bstr_t tabelka, long rekord,...);
.. w zwiakzu z tym ze nigdy nie wiem jakiego typu klase dostane, uzyje "...", gdzie wpisze swoja klase ktora chce zapisac do db bo klasy moga byc zupelnie rozne od siebie (np FVT albo NABYWCA, PLATNOSC, etc) a funkcja ta ma byc uniwersalna dla kazdej z nich.

Istnieje jakis rozsadny na to sposob?


dzieki
b

---------------
update:
potrzebuje to dlatego ze klasy (i schmeaty tabelek) sa czesto modyfikowane a w programie wiele razy odnosze sie w roznych funkacjach do zapisu jedej klasy na jakies tabelce i jakiejs db, nie chce mi sie za kazdym razem przechodzic przez wszystko i odpowiednio modyfikowac, chcialbym tylko zmodyfikowac raz typ kasy (np dodajac jakas zmienna) a zeby program juz sam wszystko zrobil za mnie.
P-93368
Monika90
» 2013-10-08 18:35:20
Możliwości jest wiele...
1. Użyj języka który nadaje się lepiej niż C++ do takich rzeczy. Ruby + Active Record?
Albo
2. Sztuczki z makrami.
Albo
3. Trzymaj dane w std::tuple i używaj metaprogramowania.
Albo
4. Napisz generator kodu, który wygeneruje klasy i kod operujący na nich na podstawie jakiejś specyfikacji.
Albo
5. Techniki obiektowe, tzn. klasa jest sama odpowiedzialna za zapis i odczyt swoich własnych danych. Wtedy każda modyfikacja oznacza zmiany tylko w jednym miejscu programu, tzn. w jednej klasie.
P-93369
berkov
Temat założony przez niniejszego użytkownika
» 2013-10-08 23:01:38
@Monika,
Nie szukasz przypadkiem meza? :-)


sorry, musialem zapytac...

1. Użyj języka który nadaje się lepiej niż C++ do takich rzeczy. Ruby + Active Record?
- Duzo kodu juz mam w c++, jakos sie lubimy, nie chce zmieniac c++ na cos innego, za duzo krwi mnie to kosztowalo :-)
2. Sztuczki z makrami.
- brzmi dobrze, chyba nawet najlepiej, moglabys przytoczyc jakis troche bardziej konkretny przyklad prosze?
3. Trzymaj dane w std::tuple i używaj metaprogramowania.
- metaprogramowanie, to nie to za bardzo to o co mi chodzilo ale wezme pod uwage jak wyczerpie inne opcje.
4. Napisz generator kodu, który wygeneruje klasy i kod operujący na nich na podstawie jakiejś specyfikacji.
- hmmmm... nawet sobie tego wyobrazic nie potrafie... :-)
5. Techniki obiektowe, tzn. klasa jest sama odpowiedzialna za zapis i odczyt swoich własnych danych. Wtedy każda modyfikacja oznacza zmiany tylko w jednym miejscu programu, tzn. w jednej klasie.
- jezeli makra nie wypala to ten pomysl podoba mi sie najbardziej, przynaje ze nie pomyslalem zeby sytuacje "odwrocic" :-)


czyli innymi slowy nie da sie dostac do klasy bez nazwy zmiennej? przez np jakis "index"?


dzieki
b
P-93385
Monika90
» 2013-10-09 22:16:04
Nie szukasz przypadkiem meza? :-)
Jestem za młoda na męża. Poza tym, to nie te czasy, mamy XXI wiek i mężowie w ogóle nie są w modzie.

2. Sztuczki z makrami.
- brzmi dobrze, chyba nawet najlepiej, moglabys przytoczyc jakis troche bardziej konkretny przyklad prosze?
Chodziło o coś jak to:
C/C++
class FVT
{
    ATTRIBUTE( long, lp );
    ATTRIBUTE( string, nazwa );
    ATTRIBUTE( double, cena );
};
Makro ATTRIBUTE dodaje deklarację do klasy i jednoczesnie rejestruje nazwę, typ, i co jeszcze potrzebne w jakiejś strukturze danych, tak że te metadane są potem dostępne dla programu. Ale nie wiem jak to zrobić żeby nie było istotnego kosztu związanego z każdym obiektem klasy FVT.

4. Napisz generator kodu, który wygeneruje klasy i kod operujący na nich na podstawie jakiejś specyfikacji.
- hmmmm... nawet sobie tego wyobrazic nie potrafie... :-)
Chodzi o to, że piszesz program który czyta opis klas z pliku i generuje pliki źródłowe w C++ z definicjami tych klas. Są one następnie kompilowane przez kompilator.

czyli innymi slowy nie da sie dostac do klasy bez nazwy zmiennej? przez np jakis "index"?
Łatwego sposobu nie ma. std::tuple daje dostęp przez indeks, ale za to nie daje przez nazwę.
P-93454
berkov
Temat założony przez niniejszego użytkownika
» 2013-10-10 18:16:18
Monika,
HAHA, moda na meza juz minela, ku zadowoleniu glownie mezczyzn, szkoda jeszcze tylko ze moda na dzieci wciaz trwa :-)

Nie moglem nic znalezc o ATTRIBUTE, to zbyt popularne ang slowe szczegolnie w programowaniu zeby google cos wyrzucilo... masz jakas dokumentacje?

Twoje rozwiazania nasunely mi jeszcze jeden pomysl... sam sobie zrobie taki "index" i oprocz zmiennych roznego typu w strukturze, poprostu stworze tablice index[], ktora bedzie przechowywac wskazniki do moich zmiennych, jest to o tyle fajne ze sam zadecyduje co i w jakiej kolejnosci "indeksowac"...  niestety z tym rozwiazaniem mam dwa inne problem:

1. Potrafie utworzyc tablice wskaznikow roznego typu ale jak tylko chce sie do kotregos dostac dostaje komunikat:
ERROR: Expression must be a pointer to a complete object type.
moj kod:
C/C++
class FVT
{
public:
    long lp;
    _bstr_t nazwa;
    double ilosc;
    _bstr_t jm;
    double cena;
    _bstr_t vat;
    double netto;
    double brutto;
   
    void * index[ 8 ];
    void INDEKSUJ();
};

void FVT::INDEKSUJ()
{
    index[ 0 ] = & lp;
    index[ 1 ] = & nazwa;
    index[ 2 ] = & ilosc;
    index[ 3 ] = & jm;
    index[ 4 ] = & cena;
    index[ 5 ] = & vat;
    index[ 6 ] = & netto;
    index[ 7 ] = & brutto;
}
i zalozmy, ze teraz chce sie dostac do lp przez index[0]:
C/C++
FVT * fvt = new FVT;
ZeroMemory( fvt, sizeof( FVT ) );
fvt->INDEKSUJ();
* fvt->index[ 0 ] = 1; //to tu fvt jest podkreslone na czerwono z komunikatem: ERROR: Expression must be a pointer to a complete object type.
probowalem rowniez najpierw utowrzyc wskaznik konkretnego typu zanim go przypisalem:
C/C++
void FVT::INDEKSUJ()
{
    index[ 0 ] = new long();
    index[ 0 ] = & lp;
    ...
}
ciagle ten sam blad kompilatora (czyli moj).


2. Zalozmy ze problem j/w uda sie rozwiazac...
Czy da sie jakos dowiedziec jakiego typu jest zmienna majac tylko sam wskaznik na nia np. index[0] ?
P-93484
DejaVu
» 2013-10-10 18:23:42
Poczytaj o dziedziczeniu, metodach wirtualnych i rzutowaniach. Musisz utworzyć klasę bazową, która będzie rozpoznawała jakiego jest typu na podstawie zapisanych w nim danych.
P-93485
Monika90
» 2013-10-11 17:18:09
szkoda jeszcze tylko ze moda na dzieci wciaz trwa :-)
Niestety trwa, a planeta jest przeludniona. Możesz dołączyć do naszego ruchu http://www.vhemt.org​/plindex.htm

Nie moglem nic znalezc o ATTRIBUTE
Chodziło o to, że ATTRIBUTE masz sobie zdefiniować samemu.

Ale popatrz na to
C/C++
#include "dbrecord.hpp"
#include <iostream>

struct Employee
    : public DBRecord < Employee >
{
    static constexpr const char * table_name = "Employees";
   
    std::string name;
    int age;
    double height;
    std::string address;
   
    static void attributes()
    {
        DECLARE( name );
        DECLARE( age );
        DECLARE( height );
        DECLARE( address );
    }
};

int main()
{
    Employee e;
    e.name = "Barack"; e.age = 52; e.height = 1.49; e.address = "Hawaii";
    e.insert( std::cout );
}
Wynik działania
INSERT INTO Employees (name,age,height,address,) VALUES ('Barack','52','1.49','Hawaii',);

Plik dbrecord.hpp
C/C++
#ifndef DBRECORD_HPP_INCLUDED
#define DBRECORD_HPP_INCLUDED
#include <sstream>
#include <vector>

template < class Record >
class AttributeBase
{
public:
    AttributeBase( const char * name )
        : name_( name )
    { }
    const char * name() const { return name_; }
    virtual std::string to_string( const Record * ) const = 0;
    virtual void from_string( Record *, const char * ) const = 0;
    virtual ~AttributeBase() = default;
   
private:
    const char * name_;
};

template < class Record, class T >
class Attribute final
    : public AttributeBase < Record >
{
public:
    Attribute( const char * name, T Record::* attr )
        : AttributeBase < Record >( name )
        , attr_( attr )
    { }
   
    std::string to_string( const Record * rec ) const override
    {
        std::ostringstream ss;
        ss << rec->* attr_;
        return ss.str();
    }
   
    void from_string( Record * rec, const char * str ) const override { /*to be implemented*/ }
   
private:
    T Record::* attr_;
};

template < class Derived >
class DBRecord
{
public:
    void insert( std::ostream & ) const;
   
protected:
    typedef Derived DerivedType;
   
    template < class T >
    static void declare( const char * name, T Derived::* attr )
    {
        attrs_.push_back( new Attribute < Derived, T >( name, attr ) );
    }
   
private:
    static std::vector < AttributeBase < Derived >*> attrs_;
};

template < class Derived >
std::vector < AttributeBase < Derived >*> DBRecord < Derived >::attrs_;

template < class Derived >
void DBRecord < Derived >::insert( std::ostream & out ) const
{
    static int call_once =( Derived::attributes(), 0 );
    out << "INSERT INTO " << Derived::table_name << " (";
    for( auto a: attrs_ ) out << a->name() << ',';
   
    out << ") VALUES (";
    for( auto a: attrs_ ) out << '\'' << a->to_string( static_cast < const Derived *>( this ) ) << "',";
   
    out << ");\n";
}

#define DECLARE(name) declare(#name, &DerivedType::name)

#endif

Do tego kodu mogę napisać parę istotnych uwag, ale to później.
P-93516
b00rt00s
» 2013-10-11 19:52:26
Tak na siłę, to można się jeszcze bawić arytmetyką wskaźników, która również dotyczy klas i obiektów. Żeby było śmieszniej, dzięki temu możesz uzyskać z zewnątrz dostęp nawet do prywatnych składowych. Jest to co prawda przykład bardzo złych praktyk programistycznych, no ale da się...
P-93523
« 1 »
  Strona 1 z 1