使用多态时如何避免向下转换?
How to avoid down cast when using polymorphism?
考虑以下设计:
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
(RawDataA
& RawDataB
)。 RawDataA
将被解码为 MessageA
,而 RawDataB
将被解码为 MessageB
。 RawDataA
和 RawDataB
共享一些共同的数据,因此 RawDataBase
被创建为基础 class。
从 MessageBase
.
派生的 MessageA
和 MessageB
也是如此
然后,在MessageBase
中添加一个虚Decode
函数,以一个RawDataBase
对象作为参数。但是 MessageA
中存在一些问题
和 MessageB
。对于 MessageA
,参数实际上应该始终是 RawDataA
,因此必须在此处进行向下转换。但是有人说必须在代码中使用向下转换时一定存在一些设计问题。
所以我的问题是如何设计这里的代码以避免向下转换?
谢谢!
这里为了避免向下转换:
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){/* ... */}
// ...
};
考虑以下设计:
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
(RawDataA
& RawDataB
)。 RawDataA
将被解码为 MessageA
,而 RawDataB
将被解码为 MessageB
。 RawDataA
和 RawDataB
共享一些共同的数据,因此 RawDataBase
被创建为基础 class。
从 MessageBase
.
MessageA
和 MessageB
也是如此
然后,在MessageBase
中添加一个虚Decode
函数,以一个RawDataBase
对象作为参数。但是 MessageA
中存在一些问题
和 MessageB
。对于 MessageA
,参数实际上应该始终是 RawDataA
,因此必须在此处进行向下转换。但是有人说必须在代码中使用向下转换时一定存在一些设计问题。
所以我的问题是如何设计这里的代码以避免向下转换?
谢谢!
这里为了避免向下转换:
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){/* ... */}
// ...
};