2009-08-31 15 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 numum MYTYPE { MYINT、MYFLOAT、...}
  2. の文字列化された列挙型のデータを文字列化した後に、DB情報を書き出します。
  3. 文字列化された列挙型をそのデータと一緒に、std::vector<string>のような文字列化されたコンテナに読み込みます。
  4. stringized-enumから実際の列挙型を抽出し、単純なスイッチケースステートメントを使用して、ストリング化データを実際のデータに変換します。文字列化列挙型を作成し、それらをリンクherehereに従って使用する方法について

。マクロのアプローチ。あるいは、テンプレート化されたapprocahを使用することができます。これは、以下のようなboost(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(...)が関数の実際の署名である場合、これも不正です - エリプシスの前に少なくとも1つの実際のパラメータが存在する必要があります
  • _SyncTypeテンプレートパラメータが使用されていないようです
  • すべてのあなたの列挙値に番号を付けるということは私にあなたが後で明示的にこれらの数字を使用することをひそかに疑いをgioves - これは悪い習慣です
  • 私は本当に「あなたのクラスが_ValueTypes自身がドンないことを何が表示されませんdo do
2

私の最初のアプローチは、を使用することです自分で作成するのではなく、またはBoost anyです。

0

これは私にはあまりにも複雑です。私は適切な型の単純なstlベクトルとして列を実装し、私は必要に応じてこれから進化させます。このデータ構造についてあまり考えすぎないようにするか、あまり複雑すぎるデザインを作成してください。