在C++中创建动态类型

Dan*_*Dan 10 c++ inheritance templates design-patterns

我正在编写一个通用软件,它将加载到同一基本硬件的许多不同变体上.它们都具有相同的处理器,但具有不同的外围设备和它们自己需要执行的功能.通过读取硬件开关值,软件将知道应该运行哪个变体.

这是我目前的实现,简而言之:

class MyBase
{
public:
    MyBase() { }
    virtual run() = 0;
}


class VariantA : public MyBase
{
public:
    VariantA () { }
    virtual run()
    {
        // Run code specific to hardware Variant-A
    }
}


class VariantB : public MyBase
{
public:
    VariantB () { }
    virtual run()
    {
        // Run code specific to hardware Variant-B
    }
}


void main()
{
    MyBase* variant;
    uint_8 switchValue = readSwitchValue();

    switch(switchValue)
    {
    case 0:
        variant = new VariantA();
        break;

    case 1:
        variant = new VariantB();
        break;
    }

    variant->run();
}
Run Code Online (Sandbox Code Playgroud)

现在这个工作得很好.我读取了硬件值并使用switch语句来创建新的相应类.

问题是我必须处理很多变种.目前约有15个,有可能在不久的将来再增加20-30个.我真的很鄙视那些运行数百行的switch语句,所以我真的在寻找一种更好的方法,可能是通过模板.

我希望能够使用我的硬件值来查找类型并使用该类型来创建我的新对象.理想情况下,当我添加一个新变体时,我创建了新类,将该类类型添加到我的查找表中,并使用匹配的硬件值,这样做很好.

这有可能吗?这里有什么好的解决方案?

pad*_*ddy 16

如上所述,您是一个工厂,但不一定是天真的开关语句.你可以做的是创建一个模板类来创建相关对象并动态地将它们添加到你的工厂.

class VariantinatorBase {
  public:
    VariantinatorBase() {}
    virtual ~VariantinatorBase() {}
    virtual std::unique_ptr<Variant> Create() = 0;
};

template< class T >
class Variantinator : public VariantinatorBase {
  public:
    Variantinator() {}
    virtual ~Variantinator() {}
    virtual std::unique_ptr<Variant> Create() { return std::make_unique<T>(); }
};
Run Code Online (Sandbox Code Playgroud)

现在你有一个允许你注册这些的类工厂.

class VariantFactory
{
  public:
    VariantFactory()
    {
         // If you want, you can do all your Register() calls in here, and even
         // make the Register() function private.
    }

    template< uint_8 type, typename T >
    void Register()
    {
        Register( type, std::make_unique<Variantinator<T>>() );
    }

    std::unique_ptr<Variant> Create( uint_8 type )
    {
        TSwitchToVariant::iterator it = m_switchToVariant.find( type );
        if( it == m_switchToVariant.end() ) return nullptr;
        return it->second->Create();
    }

  private:
    void Register( uint_8 type, std::unique_ptr<VariantinatorBase>&& creator )
    {
        m_switchToVariant[type] = std::move(creator);
    }

    typedef std::map<uint_8, std::unique_ptr<VariantinatorBase> > TSwitchToVariant;
    TSwitchToVariant m_switchToVariant;
};
Run Code Online (Sandbox Code Playgroud)

在程序开始时,创建工厂并注册您的类型:

VariantFactory factory;
factory.Register<0, VariantA>();
factory.Register<1, VariantB>();
factory.Register<2, VariantC>();
Run Code Online (Sandbox Code Playgroud)

然后,你要打电话给它:

std::unique_ptr<Variant> thing = factory.Create( switchValue );
Run Code Online (Sandbox Code Playgroud)

  • @paddy如果需要,您仍然可以选择将返回的`unique_ptr`转换为`shared_ptr`.返回`unique_ptr`清楚地表明指针的所有权被传递给调用者并防止内存泄漏. (3认同)
  • +1我喜欢这个设计.一些改进的想法:1.向`VariantinatorBase`添加一个虚拟析构函数.2.(当使用C++ 11时)使`Create`方法返回`std :: unique_ptr <Variant>`而不是原始指针.3.(当使用C++ 11时)同样,将`std :: unique_ptr <VariantinatorBase>`传递给`VariantFactory :: Register`. (2认同)
  • 当然可以将代码重复减少到只有`Register <VariantA>(0);`如果允许模板`Register`函数知道`Variantator`. (2认同)
  • 哈,五年后我终于在将其链接到某人后回到这个问题,并进行了所需的更改。 (2认同)