2009-08-31 7 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에서 정렬 또는 필터링이 더 빠를 것입니다. –

답변

1

DB 동작을 에뮬레이트하는 경우 'type'의 컨테이너에 데이터를 저장하는 것이 좋습니다. 데이터는 열 이름을 통해 액세스되므로 각 열에 대한 데이터 값을 저장하고 열 이름에서 열 유형으로 매핑하는 컨테이너가 있어야합니다. 당신은 그 형태와 함께 데이터를 저장할 어쨌든이라면 '열거의 stringization'를 사용하여 다음과 같은 방법을 고려하십시오 -

  1. 은 유형에 대한 자신의 열거를 상수를 만듭니다. like enum MYTYPE { MYINT, MYFLOAT, ...}
  2. 문자열 화 된 enum 아래의 데이터를 문자열화한 후 DB 정보를 씁니다.
  3. 해당 데이터와 함께 stringized-enum을 std::vector<string>과 같은 문자열 화 된 컨테이너로 읽습니다.
  4. 문자열 화 된 enum에서 실제 열거 형을 추출한 다음 간단한 switch case 문을 사용하여 문자열 화 된 데이터를 실제 데이터로 변환하십시오.

문자열 화 된 enum을 생성하고이를 사용하는 방법은 herehere입니다. 매크로의 접근 방식. 또는 아래처럼 부스트를 사용해야하는 templatized approcah를 사용할 수 있습니다 (힌트 :-)).

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 템플릿 매개 변수가 사용 된 것 같지 않습니다.
  • 사실 모든 enum 값에 번호를 매기면 나중에 명시 적으로 그 숫자를 명시 적으로 사용하려는 의심의 여지가 생깁니다. 이것은 나쁜 습관입니다.
  • _ValueTypes 자체가 ' do
2

내 첫 번째 방법은을 사용하는 것입니다. 내 자신을 생성하는 대신또는 Boost any

0

이것은 지나치게 복잡합니다. 나는 적절한 타입의 간단한 stl vector로 column을 구현할 것이고, 필자는 필요할 때마다 이것을 전개 할 것이다. 이 데이터 구조에 대해 너무 열심히 생각하지 않으면 지나치게 복잡한 디자인을 만들게됩니다.

관련 문제