2012-02-15 6 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>이 'alignment'이면 메시지 해석기가 정렬 구조체를 작성한 다음이를 반환합니다.

궁극적으로 나는 <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_; 
} 

이 다형성없이 작동

(당신에게 아이디어를 제공하기 위해 검증없이 코딩) (I를 다형성 트리가 더 복잡한 코드가되는 LISP와 같은 언어 용 컴파일러에서이 패턴을 사용하십시오. 원한다면 "alignment_x()"를 반환하도록 변경할 수 있습니다.

완전히 동적 인 구조는 불가능하며 가까이 오려고하는 솔루션은 다소 복잡합니다. 가장 유지 보수가 쉬운 솔루션을 사용하십시오.

0

각 유형에 대한 팩토리 함수/펑터를 작성하면 messageType (map<string, Factory*>이면 충분)과 연결할 수 있지만 반환 할 대상은 무엇입니까?

가능한 모든 메시지 유형에 따라 최상위 디코더가 마음에 들지 않는 경우 일종의 차별화 된 공용체 또는 boost::variant을 반환 할 수 있습니다.

하지만이 반환 값으로 수행 할 디코더는 무엇입니까? 형식을 켜고 각 경우마다 유형별 콜백을 호출하면 콜백 함수/펑터를 직접 공장에 연결하여 제어를 반전시킬 수 있습니다.

그런 다음 디코더는 아무 것도 반환하지 않고 메시지 struct을 생성하고 직접 처리기로 전달합니다.

간단한 구현 (OK, 그것이 내가 생각했던 것보다 더 입력했다),

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

QMetaObject :: 위해서, newInstance를 사용하면

dynamic_cast는 사용하여 클래스 이후에 변환 할 수있는 QObject의 *을 만들 수 있도록
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); 

그리고 일 위스콘신 잘될거야.