我写了很多处理消息协议的代码。消息协议通常会具有通用的消息帧,可以从串行端口或套接字反序列化。该帧包含消息类型,并且必须根据消息类型来处理消息有效负载。
通常,我用访问器方法和构造函数编写一个多态类集,该构造函数引用消息框。
我想到的是,我可以直接从消息框架派生访问器类,然后从消息框架重新解释_cast到适当的访问器类,而不是基于对消息框架的引用来构造访问器类。这使代码更加简洁,并节省了一些字节和处理器周期。
请参见下面的示例(极度虚构和压缩)。显然,对于生产代码,所有这些都需要适当地封装,强制转换成为派生类的成员,更好地分离了所关注的问题,并添加了一些验证。为了简洁起见,已全部删除。
#include <iostream>
#include <cstring>
#include <vector>
struct GenericMessage
{
GenericMessage(const char* body):body_(body, body+strlen(body)){}
std::vector<char> body_;
};
struct MessageType1:public GenericMessage
{
int GetFoo()const
{
return body_[2];
}
int GetBar()const
{
return body_[3];
}
};
int main()
{
GenericMessage myGenericMessage("1234");
MessageType1* myMgessageType1 = reinterpret_cast<MessageType1*>(&myGenericMessage);
std::cout << "Foo:" << myMgessageType1->GetFoo() << std::endl;
std::cout << "Bar:" << myMgessageType1->GetBar() << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我从来没有见过任何地方这样做。考虑到派生没有其他数据成员,以这种方式从基础到派生有任何不利之处吗?
这就是为什么我不使用这种技术的原因:
这违反了标准,导致行为未定义。的确,这几乎一直都有效,但是您不能排除将来的问题。人们已经看到编译器在优化中使用了未定义的行为,这对毫无疑问的程序员是不利的。而且您无法预测何时,在何种情况下会发生这种情况。
您不能保证您和队友都不会将某些数据成员添加到派生类型。随着时间的推移,您的类层次结构将不断增长,并且将添加更多代码;在某些时候,对于您或其他程序员而言,将一个无辜的数据成员添加到派生类型(即使是临时性的,也许出于某种调试目的)可能并不明显,这可能会带来灾难。
有一些合法的替代方法,例如,根据引用使用包装器:
#include <iostream>
struct Elem
{ };
struct ElemWrapper
{
Elem &elem_;
ElemWrapper(Elem &elem) : elem_(elem)
{ }
};
struct ElemWrapper1 : ElemWrapper
{
using ElemWrapper::ElemWrapper;
void foo()
{ std::cout << "foo1" << std::endl; }
};
struct ElemWrapper2 : ElemWrapper
{
using ElemWrapper::ElemWrapper;
void foo()
{ std::cout << "foo2" << std::endl; }
};
int main()
{
Elem e;
ElemWrapper1(e).foo();
return 0;
}
Run Code Online (Sandbox Code Playgroud)| 归档时间: |
|
| 查看次数: |
1376 次 |
| 最近记录: |