【问题标题】:How to avoid down cast when using polymorphism?使用多态时如何避免向下转换?
【发布时间】:2018-01-18 08:58:06
【问题描述】:

考虑以下设计:

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 时遇到了设计问题。

RawData 有两种类型(RawDataARawDataB)。 RawDataA 将被解码为MessageA,而RawDataB 将被解码为MessageBRawDataARawDataB 都共享一些公共数据,因此 RawDataBase 被创建为基类。 派生自MessageBaseMessageAMessageB 也是如此。

然后,将一个虚拟的Decode 函数添加到MessageBase 中,以RawDataBase 对象为参数。但是MessageA有问题 和MessageB。对于MessageA,参数实际上应该总是RawDataA,所以这里必须进行向下转换。但是有人说,当必须在代码中使用向下转换时,肯定存在一些设计问题。

所以我的问题是如何设计这里的代码以避免向下转换?

谢谢!

【问题讨论】:

  • template 在这里分解代码似乎比继承更好。
  • 你也是指 CRTP 吗?或其他解决方案。谢谢!
  • 不需要CRTP,一个简单的模板类。

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


【解决方案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){/* ... */}

    // ...
};

【讨论】:

  • 酷!这解决了我的问题:-) 感谢您的帮助!
  • 它不是 CRTP,它是为 class Derived : public Base&lt;Derived&gt; 准备的。这里是模板类的简单继承。
  • @Jarod42 你是对的,我的错。我编辑了我的答案。谢谢 :)
猜你喜欢
  • 2014-08-12
  • 2014-11-26
  • 1970-01-01
  • 2014-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多