避免静电和放电动态铸造

时间:2017-05-08 22:01:35

标签: c++ oop downcast

我正在更新接收多播消息的系统,将数据解析为类,然后通过 指向通过队列的单独线程的基类指针。然后另一个线程读取数据 从类中,将它们存储在表中。

我们收到两种不同类型的邮件。这是班级设计:

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;
}

这是接收代码:

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);
}

这是在单独的线程中运行的流程代码:

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
    }
}

我知道检查消息类型然后向下转发是草率的,但考虑到沟通的限制 通过队列,我无法想出更好的解决方案。即使使用dynamic_cast&lt;&gt; (哪一个 我出于性能原因不想这样做会带来同样的问题;它仍然需要知道 将msgToProcess转换为什么类型的类。

关于如何摆脱支票的任何建议&amp;铸件?我有很多经验 与C&amp; C ++,但OO设计并不多,所以可能有一种我一无所知的方式。

另请注意,这是一个非常精简的示例来说明问题。那里 实际上超过50种不同的消息类型,性能至关重要,正如我们所能收到的那样 每秒数百万条消息。

2 个答案:

答案 0 :(得分:3)

我同意其他建议使用多态性的固有属性并使用成员函数的人。

但我也理解保持消息类非常干净的必要性。我认为在这种情况下使用访问者模式(依赖于多态)可能是一个好主意:

class BaseMsg {
public:
    virtual void accept(MsgProcessor& p) = 0;
};

class Msg1 : BaseMsg {
public:
    void accept(MsgProcessor& p) { p.process(*this); }
};

class Msg2 : BaseMsg {
public:
    void accept(MsgProcessor& p) { p.process(*this); }
};

class MsgProcessor {
public:
    void process(Msg1& m);
    void process(Msg2& m);
}

很酷的是,如果任何派生类缺少其中一个函数,则无法编译。

编辑:修复了评论中指出的内容

edit2:有两个代码库&amp;外部代码库中的最小变化:

外部代码库:

class MsgVisitor;
class BaseMsg {
public:
    virtual void accept(MsgVisitor&) = 0;
};

class Msg1;
class Msg2;
class MsgVisitor {
public:
    virtual void visit(Msg1&) = 0;
    virtual void visit(Msg2&) = 0;
};

class Msg1 : public BaseMsg {
public:
    void accept(MsgVisitor& v) { v.visit(*this); }
};

class Msg2 : public BaseMsg {
public:
    void accept(MsgVisitor& v) { v.visit(*this); }
};

本地代码库:

class MsgProcessor : public MsgVisitor {
public:
    void visit(Msg1& m) { ... } // do stuff for Msg1
    void visit(Msg2& m) { ... }
};

void processMessage(MsgQueue *queue)
{
    BaseMsg *msgToProcess = queue->pop();
    msgToProcess->accept(MsgProcessor());
    //delete msgToProcess;
}

答案 1 :(得分:2)

我会在类doStuff()中定义一个名为BaseMsg的纯虚函数。
每个派生类都实现该方法 在processMessage内,您只需致电msgToProcess->doStuff()