C ++设计:从基类转换为派生类,没有额外的数据成员

Sim*_*ott 6 c++ inheritance

我写了很多处理消息协议的代码。消息协议通常会具有通用的消息帧,可以从串行端口或套接字反序列化。该帧包含消息类型,并且必须根据消息类型来处理消息有效负载。

通常,我用访问器方法和构造函数编写一个多态类集,该构造函数引用消息框。

我想到的是,我可以直接从消息框架派生访问器类,然后从消息框架重新解释_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)

我从来没有见过任何地方这样做。考虑到派生没有其他数据成员,以这种方式从基础到派生有任何不利之处吗?

jog*_*pan 5

这就是为什么我不使用这种技术的原因:

  1. 这违反了标准,导致行为未定义。的确,这几乎一直都有效,但是您不能排除将来的问题。人们已经看到编译器在优化中使用了未定义的行为,这对毫无疑问的程序员是不利的。而且您无法预测何时,在何种情况下会发生这种情况。

  2. 您不能保证您和队友都不会将某些数据成员添加到派生类型。随着时间的推移,您的类层次结构将不断增长,并且将添加更多代码;在某些时候,对于您或其他程序员而言,将一个无辜的数据成员添加到派生类型(即使是临时性的,也许出于某种调试目的)可能并不明显,这可能会带来灾难。

  3. 有一些合法的替代方法,例如,根据引用使用包装器:

    #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)

  • 我想,如果您忽略这个问题的事实,即“通常我会编写一组具有访问器方法和一个引用消息帧的构造函数的多态类”,那么这个答案就可以了。- 这基本上是您建议的替代“解决方案”,当他没有要求解决方案时,而是“考虑到派生没有额外的数据成员,以这种方式从基类转换为派生的任何缺点”,这可以很容易地由代码生成器(通常在这些场景中使用)或静态分析强制执行。 (2认同)