使用多态时如何避免向下转换?

时间:2017-08-10 08:18:58

标签: c++ inheritance design-patterns static-cast

考虑以下设计:

class RawDataBase
{
private:    
    std::string data;
};

class RawDataA : public RawDataBase
{
private:    
    int spec_data_for_a1;
    int spec_data_for_a2;
};

class RawDataB : public RawDataBase
{
private:    
    int spec_data__for_b;
};

class MessageBase
{
private:    
    int x;
    int y;
    int z;
public:
    virtual void Decode(RawDataBase *raw)
    {
        // extract x,y,z from raw.data
    }
};

class MessageA : public MessageBase
{
private:    
    int spec_data_for_a1;
    int spec_data_for_a2;
public:
    /* Here raw must be RawDataA*/
    virtual void Decode(RawDataBase *raw)
    {
        MessageBase::Decode(raw);
        RawDataA raw_data = static_cast<RawDataA*>(raw);
        // extract spec_data_for_a1, spec_data_for_a2 from raw_data
    }
};

class MessageB : public MessageBase
{
private:    
    int spec_data__for_b;
public:
    /* Here raw must be RawDataB*/
    virtual void Decode(RawDataBase *raw)
    {
        MessageBase::Decode(raw);
        RawDataB raw_data = static_cast<RawDataB*>(raw);
        // extract spec_data__for_b from raw_data       
    }
};

RawData解码为Message时,我遇到了设计问题。

RawDataRawDataA&amp; RawDataB)有两种类型。 RawDataA将被解码为MessageA,而RawDataB将被解码为MessageBRawDataARawDataB都共享了一些公共数据,因此RawDataBase被创建为基类。 从MessageA派生的MessageBMessageBase也是如此。

然后,在Decode中添加一个虚拟MessageBase函数,将RawDataBase个对象作为参数。但MessageA存在一些问题  和MessageB。对于MessageA,参数实际上应始终为RawDataA,因此必须在此处完成降级。但有人说,必须在代码中使用向下转换时必须存在一些设计问题。

所以我的问题是如何在这里设计代码以避免失败?

谢谢!

1 个答案:

答案 0 :(得分:1)

为了避免失败:

class MessageA : public MessageBase {
    virtual void Decode(RawDataBase *raw) { ...}
}

你的代码必须是这样的:

class MessageA : public MessageBase {
    virtual void Decode(RawDataA *raw) { ...}
}

这意味着MessageBase必须以某种方式成为:

class MessageBase {
    virtual void Decode(RawDataA *raw){...}
}

这可以使用以下模板完成:

class RawDataBase { /* ... */ };
class RawDataA : public RawDataBase { /* ... */ }; 
class RawDataB : public RawDataBase { /* ... */ };

template<typename T>
class MessageBase {

    using RawDataType = T;

    // ...

    virtual void Decode(RawDataType *raw){/* ... */}

    // ...

};

class MessageA : public MessageBase<RawDataTypeA> {
    // ...

    virtual void Decode(RawDataType *raw){/* ... */}

    // ...
};

class MessageB : public MessageBase<RawDataTypeB> {
    // ...

    virtual void Decode(RawDataType *raw){/* ... */}

    // ...
};