2012-02-15 79 views
1

我有一個應用程序將從另一個應用程序接收消息。這些消息將是XML格式化的字符串,它們將包含一個<messageType>標籤。消息類型將將此消息標識爲內部消息的一種類型。以下代碼顯示了我的內部消息結構。模板類C++/Qt

namespace 
Application1{ 

enum ApplicationAttributes{ 
    ApplicationName = 1000, 
    Start, 
    Stop, 
    Pause, 
    Save, 
    Discard, 
    SelectRunway, 
    DoAlignment, 
    RedoAlignment, 
    AlignmentOK, 
    DoCalibrationStage1, 
    SetCalibrationStage1, 
    SetCalibrationStage2, 
    SetCalibrationStage3, 
    CancelCalibration, 
    CalibrationOK 
}; 


struct Alignment{ 
    int x; 
    int y; 
    int error; 
}; 

struct Calibration{ 
    int x; 
    int y; 
    int error; 
}; 

} 

校準和校準是兩個內部消息結構。

我想要做的是構建一個'消息解釋器',它將接收一個XML字符串,解碼並返回上面顯示的任何一個結構;所以如果<messageType>是「對齊」,則消息解釋器將構建對齊結構,並返回該對齊結構。

因此,最終,我試圖做一個模板函數,它可以返回一個任意的結構,基於我從<messageType>中讀取的內容。

我的目標是否清晰?我的方法是正確的嗎?

讓我知道我是否應該澄清,或者如果我應該採取不同的方法。

回答

3

我不相信模板函數是有道理的。你的輸入總是一個字符串,而C++不能根據返回類型單獨區分函數簽名 - 所以我不知道模板會如何幫助 - 類型參數是什麼?

我建議讓你的函數成爲一個正常的函數,解析出messageType並根據它分配一個結構 - 你可以使用任何你想要的結構。

訣竅是(在我的腦海中)從同一個空基類中派生所有的內部消息類 - 然後你可以從你的函數返回一個指向該基類的指針,它將保存任何類型被創建。

將一個枚舉與std :: pair中的指針一起返回是個好主意,您可以使用它來確定創建的正確派生類型,這樣您可以直接將結果轉換爲正確的派生類型與static_cast。

0

據我瞭解你的結構是在應用程序中已知的,所以你看這個保存的變體:

class Message { 
public: 
    static Message Alignment (alignment_t const &); 
    ... 
    Type type() const; 

    int alignment() const; 

private: 
    Message (Type t); 
    assert_type (Type t, const char *msg) const; 

private: 
    Type type_; 
}; 

Message Message::Alignment (alignment_t const &alignment) 
{ 
    Message ret (Type::Alignment); 
    ret.alignment_ = alignment; 
    return ret; 
} 

void Message::assert_type (Type t, const char *msg) const 
{ 
    if (type() != t) throw std::runtime_error (msg); 
} 

int Message::alignment() const 
{ 
    assert_type (Type::Alignment, 
       "alignment_x() called for non-alignment-message"); 
    return alignment_; 
} 

(無驗證碼給你的想法)

此作品,未經多態性(我在類似LISP的語言的編譯器中使用此模式,其中多態樹會導致更復雜的代碼)。你可以改變它返回「alignment_x()」等等,如果你更喜歡那樣的話。

完全動態的結構是不可能的,嘗試靠近的解決方案將是相當複雜的。使用最易維護的解決方案。

0

如果爲每種類型編寫工廠函數/仿函數,則可以將其與messageType關聯(map<string, Factory*>就足夠了),但返回什麼?

如果您根據所有可能的消息類型不介意頂級解碼器,則可以返回某種區分的聯合或boost::variant

但是,解碼器會用這個返回值做什麼?如果只是打開類型並在每種情況下調用特定於類型的回調函數,則可以通過直接將回調函數/仿函數附加到工廠來反轉控制。

然後解碼器不返回任何東西,它只是構造消息struct並將其直接傳遞給處理程序。

簡單實現(OK,這是更打字比我想象的):使用QMetaObject ::的newInstance

class Decoder 
{ 
public: 
    virtual ~Decoder(); 
    virtual void decode(std::string const &xml) = 0; 
}; 

template <typename Factory, typename Callback> 
class SimpleDecoder: public Decoder 
{ 
    Factory factory; 
    Callback callback; 
public: 
    SimpleDecoder(Factory f, Callback c) 
    : factory(f), callback(c) 
    {} 

    void decode(std::string const &xml) 
    { 
    callback(factory(xml)); 
    } 
}; 

std::map<std::string, Decoder*> factories; 

template <typename F, typename C> 
void registerSimpleDecoder(std::string const &n, F f, C c) 
{ 
    factories[n] = new SimpleDecoder(f, c); 
} 

void decodeXmlMessage(std::string const &messageType, std::string const &body) 
{ 
    factories[messageType]->decode(body); 
} 
0

,這樣你就可以創建一個QObject *可以使用後轉換爲類的dynamic_cast

class MyClass : public QObject{ 
    public: 
    enum Type{ MyClassType = UserType + 1 } 
    Q_INVOKABLE MyClass(); 
} 
Q_DECLARE_METATYPE (MyClass) 

然後,在你的XML解析代碼:

MyClass* myObject = (MyClass*) QMetaType::construct (MyClass::MyClassType); 

和事物的Wi會解決的。