Ich aktualisiere ein System, das Multicast-Nachrichten empfängt, analysiert die Daten in Klassen und übergibt dann einen Basisklassenzeiger an einen separaten Thread über eine Warteschlange. Der andere Thread liest dann die Daten aus den Klassen und speichert sie in Tabellen.Vermeiden Sie statische und dynamische Umwandlung
Es gibt 2 verschiedene Arten von Nachrichten, die wir erhalten. Hier ist die Klasse Design:
class BaseMsg
{
public:
BaseMsg(char tp) : msgType(tp) {}
virtual ~BaseMsg() = 0;
char msgType;
}
class MsgType1 : public BaseMsg
{
public:
MsgType1(int a, int b) : BaseMsg('1'), val1(a), val2(b) {}
virtual ~MsgType1();
int val1, val2;
}
class MsgType2 : public BaseMsg
{
public:
MsgType2(double a, double b) : BaseMsg('2'), val1(a), val2(b) {}
virtual ~MsgType2();
double val1, val2;
}
Hier ist der Empfangscode:
void reciveMessage(char *datablob, MsgQueue *queue)
{
BaseMsg *msgReceived;
char type = datablob[0]; // message type is the first character in the data,
// the rest of the blob varies based on that type
if (type == '1') {
// code for parsing type 1 into 2 ints, i1, i2
msgReceived = new MsgType1(i1, i2);
} else {
// code for parsing type 2 into 2 doubles, d1, d2
msgReceived = new MsgType2(d1, d2);
}
queue->push(msgReceived);
}
Hier ist der Prozess-Code, der in einem separaten Thread ausgeführt wird:
void processMessage(MsgQueue *queue)
{
BaseMsg *msgToProcess = queue->pop();
if (msgToProcess->msgType == '1') {
MsgType1 *mt1 = static_cast<MsgType1 *>(msgToProcess);
// do stuff with the message type 1 data
} else {
MsgType2 *mt2 = static_cast<MsgType2 *>(msgToProcess);
// do stuff with the message type 2 data
}
}
Ich weiß, dass die Prüfung für den Nachrichtentyp dann downcasting ist schlampig, aber angesichts der Beschränkungen der Kommunikation durch die Warteschlange, konnte ich nicht mit einer besseren Lösung kommen. Selbst mit dynamic_cast <> (die ich aus Leistungsgründen nicht tun möchte) würde das gleiche Problem führen; es muss immer noch wissen, welche Art von Klasse zu konvertieren msgToProcess.
Irgendwelche Vorschläge darüber, wie ich die Überprüfungen loswerden könnte & Casting? Ich habe viel Erfahrung mit C & C++, aber nicht viel mit OO-Design, so kann es einen Weg, über den ich nichts weiß.
Beachten Sie auch, dass dies ein extrem reduziertes Beispiel zur Veranschaulichung der Frage ist. Es sind tatsächlich über 50 verschiedene Nachrichtentypen, und die Leistung ist kritisch, da wir Millionen von Nachrichten pro Sekunde erhalten können.
In der "Do stuff" -Abschnitt, gibt es eine Möglichkeit, die Sie können Imp es in Bezug auf virtuelle Funktionsaufrufe in der Basisklasse? – RyanP
Sie können die Anzahl der Stellen reduzieren, an denen "downcast" verwendet wird, aber Sie können es nicht vermeiden. Siehe [meine Antwort zu einem anderen SO-Post] (http://stackoverflow.com/a/43038856/434551) für Ideen, wie man es weniger repetitiv macht. –
Wenn Sie sich nicht auf RTTI (Casting) verlassen möchten, möchten Sie vielleicht eine diskriminierende Union verwenden, aber Sie würden immer noch eine switch-Anweisung über eine enum benötigen, es gibt auch std :: variant, die einen ähnlichen Job erledigt. Ich habe die Leistung nicht ausprobiert, aber ich nehme an, dass es sehr schnell geht, da Sie keine Umleitung speichern müssen, damit Sie von der Cache-Lokalität profitieren können. – AlexG