2009-08-31 4 views
0

Я написал приложение в MFC с C++. Мне нужно написать класс, который может сохранить все данные, загруженные из базы данных. Эти данные могут содержать все типы данных, такие как int, string, byte, boolean, datetime и т. Д. Мы можем фильтровать, обменивать столбцы или сортировать эти данные. Например:Как создать класс C++?

int int string bool double float .... string 
0 1 "a" false 3.14 3.0  "b" 
1 2 "5" true 3.22 4   "c" 

Примечание: Мы не использовали SQL для сортировки или фильтра, так как у нас есть наше рассмотрение.

Мы написали следующий класс, возможно, у кого-то есть лучшее предложение, пожалуйста, напишите образец класса для использования, спасибо заранее!

#ifndef __LIST_DATA_MODEL_H__ 
#define __LIST_DATA_MODEL_H__ 

#include <vector> 
using std::vector; 

///implement a pure virtual base class; parameters of function is a void pointer, 

class FieldType 
{ 
public: 
enum { 
    TypeChar = 0, 
    TypeString = 1, 

    TypeBool = 2, 

    TypeShort = 3, 
    TypeUShort = 4, 

    TypeInt  = 5, 
    TypeUInt = 6, 

    TypeLong = 7, 
    TypeULong = 8, 

    TypeLongLong = 9, 
    TypeULongLong = 10, 

    TypeFloat  = 11, 
    TypeDouble = 12 
}; 
}; 

template <typename _ValueType, typename _SyncType> 
class Column 
{ 
protected: 
CString  m_szFieldName; 
vector<_ValueType> m_vValues; 

public: 
Column(); 
Column(CString szFieldName); 
Column(const Column& other); 
virtual ~Column(); 

public: 
virtual BOOL LoadData(...); 

public: 
///This function will call LoadData function to re-load data, 
///if subclass this class, please implement your LoadData function 
///if you want additional operation when load data. 
CALLBACK BOOL Update(); 

public: 
const int ValueCount() const; 
const CString& FieldName() const; 
const _ValueType& ValueAt(int iPos) const; 

///Before you call LoadData function or Update Function, the values will not updated; 
void SetFieldName(const CString& szFieldName); 

void SetValue(const _ValueType& val, int iPos); 
}; 

template<class _Type> 
class DataItem 
{ 
protected: 
_Type _value; 

public: 
DataItem(); 
DataItem(const DataItem& other) 
{ 
    _value = other._value; 
}; 
DataItem(const _Type& val) 
{ 
    _value = val; 
}; 
virtual ~DataItem() 
{ 
}; 

public: 
const _Type& GetValue() 
{ 
    return _value; 
}; 
void SetValue(const _Type& value) 
{ 
    _value = value; 
}; 
void ResetValue() 
{ 
    _value = _Type(); 
}; 
public: 
bool operator ==(DataItem& right) 
{ 
    return _value == right._value; 
}; 
bool operator <(const DataItem& right) 
{ 
    return _value < right._value; 
}; 
const DataItem& operator =(const DataItem& right) 
{ 
    if(this == &right) 
    return *this; 

    _value = right._value; 

    return *this; 
}; 

virtual DataItem* Clone() 
{ 
    return new DataItem(*this); 
}; 
}; 

typedef DataItem<int> IntItem; 
typedef DataItem<float> FloatItem; 
typedef DataItem<double> DoubleItem; 
typedef DataItem<CString> StringItem; 
typedef DataItem<bool>  BoolItem; 
typedef DataItem<TCHAR>  CharItem; 
typedef DataItem<char>  ByteItem; 
typedef DataItem<CString> CStringItem; 

#endif 
+4

_V является зарезервированным префиксом для компилятора и стандартной библиотеки, поэтому _ValueType является незаконным именем. То же самое относится к _A - _Z, поэтому у вас есть несколько имен, которые нужно очистить. Вы можете удалить их во всех случаях; все имена, которые вы префиксны, уже заняты, ни один из них не является глобальным. – MSalters

+2

У вас есть какие-либо советы по поводу структуры? – MemoryLeak

+4

Какое «соображение» заставило вас не использовать SQL для сортировки или фильтрации? Сортировка или фильтрация в SQL будет быстрее _lot_, потому что база данных может использовать индексы, и вы можете избежать переноса всей таблицы клиенту. –

ответ

1

Мне интересно, если вы эмулируете поведение БД, тогда имеет смысл хранить данные в контейнерах типа? Поскольку данные будут доступны через имена столбцов, вам необходимо иметь контейнеры, которые хранят значения данных для каждого столбца и имеют имя столбца для сопоставления типа столбца. В любом случае, если вы хотите хранить данные вместе с его типа, то рассмотрим следующий подход с использованием «stringization из перечислений»: -

  1. Создайте свой собственный Перечень константы для типов. Как enum MYTYPE { MYINT, MYFLOAT, ...}
  2. Выписывать информацию БД после строкой данных под каждым stringized-enum.
  3. Прочитайте строковое перечисление вместе со своими данными в контейнер с напряжением, например std::vector<string>.
  4. Извлеките фактический тип перечисления из строки stringized-enum, а затем с помощью простого оператора case switch закройте привязанные данные к фактическим данным.

О том, как создавать строковые перечисления и использовать их, следуйте по ссылке here и here. Подход Макро. Или вы можете использовать templatized approcah, который требует использования boost что-то вроде ниже (только подсказка :-)).

template<typename ENUM> 
class Stringifier<ENUM, typename boost::enable_if<boost::is_enum<ENUM> >::type> { 
    static const char * values[]; // array with the enum strings. 
    static std::size_t size;  // Number of elements of the ENUM string arrays. 
public: 
    /// Global static instance of the Stringifier. 
    static Stringifier & getInstance() 
    { 
    static Stringifier globalInstance; 
    return globalInstance; 
    } 
    // Returns the string representation of the ENUM value \a e as a C string. 
    // If string is not available an exception is thrown. 
    virtual void str(ENUM const & e, std::string & s) const 
    { 
    if(e >= 0 && e < int(size)) 
     s = values[e]; 
    else // throw exception 
    ; 
    } 

    // Returns the ENUM value of the string representation of an ENUM value if possible, 
    // ENUM(0) otherwise or ENUM(size) if you like. 
    virtual bool value(std::string const & str, ENUM & v) const 
    { 
    std::size_t i = 0; 
    for(; i < size; ++i) 
     if(values[i] == str) break; 
    bool ok = (i != size); 
    v = ok ? ENUM(i) : ENUM(0); 
    return ok; 
    } 
}; 

Используйте этот список как 'ENUM' в указанном выше классе.

ПРИМЕЧАНИЕ: Струинг убивает производительность. Таким образом, этот подход медленнее.

1

Любые причины не использовать тип данных COM _variant_t?

+1

Не является кросс-платформенным? – Arpegius

+3

MFC не является межплатформенным либо – Goz

1

Несколько пунктов о вашем коде:

  • Как MSalters указывает, имена, как _ValueType и __LIST_DATA_MODEL_H__ являются незаконными в пользовательском коде.
  • Если виртуальная BOOL LoadData (...) является реальной сигнатурой функции, это тоже является незаконным - должен существовать хотя бы один фактический параметр перед elipsis
  • параметр шаблона _SyncType, похоже, не используется
  • тот факт, что вы пронумеровать все значения перечислений gioves меня закрадывается подозрение, что вы собираетесь использовать эти цифры явно позже - это плохая практика
  • Я не очень понимаю, что ваш класс делает что _ValueTypes сами надеваете» t do
2

Моим первым подходом было бы использовать Boost variant или Boost any вместо того, чтобы создавать свои собственные.

0

Это кажется слишком сложным для меня. Я бы выполнил столбец как простой stl-вектор соответствующего типа, и я буду развиваться из него по мере необходимости. Попытайтесь не думать слишком сильно об этой структуре данных, иначе вы создадите слишком сложный дизайн.

Смежные вопросы