【问题标题】:better way to do this?更好的方法来做到这一点?
【发布时间】:2010-10-29 17:05:21
【问题描述】:

我正在做一些看起来可以改进的事情,但我没有足够的技能来改进它。你能帮忙吗?

给定:

vector<Base*> stuff;
const vector<MetaData>& metaDataContainer = Config.getMetaData();

for(vector<MetaData>::const_iterator i = metaDataContainer.begin(), end = metaDataContainer.end(); i != end; ++i)
{
  Base* pCurrent = buildDerivedType(*i);
  stuff.push_back(pCurrent);
}

Base* buildDerivedType(MetaData meta)
{
  Base* pRetval = NULL;

  switch(meta)
  {
    case MetaData::A:
    pRetval = new Alpha();
    break;

    case MetaData::B:
    pRetval = new Beta();
    break;

    //so on so forth
  };
  return pRetval;
}

我觉得 switch 语句很糟糕,因为在编译时所有的枚举值都是已知的,所以理论上我们已经知道向量的东西需要哪些类型。但我们在运行时这样做。

暂时没有为此编写代码生成器,有没有更好的方法?

【问题讨论】:

  • "在编译时所有枚举值都是已知的" - 你的意思是你知道metaDataContainer 的内容?它看起来不像那样。而switch 是实现工厂模式的好方法。
  • 你说得对,我不知道容器包含什么,但我知道它可能包含的所有可能值。因此,如果 MetaData 是带有 A、B、C 的枚举。我知道这些是可能性,但是,我可能只得到 A 和 C。

标签: c++


【解决方案1】:

不是真的。但是,您可以使用factory type 抽象出大部分样板文件,并使用boost::ptr_vector 或智能指针容器以智能方式管理资源。 (See comments 关于智能容器与智能指针哑容器之间的选择。)

【讨论】:

    【解决方案2】:

    好吧,您可以预先分配一个映射元 -> 函数来创建所需的派生类型。

    typedef Base* ((*DerivedTypeCreator)());
    map <MetaData, DerivedTypeCreator> derivedTypeBuilders;
    
    // ...
    derivedTypeBuilders[MetaData::A] = &CreateAlpha;
    derivedTypeBuilders[MetaData::B] = &CreateBeta;
    
    Base* CreateAlpha()
    {
        return new Alpha();
    }
    
    Base* CreateBeta()
    {
        return new Beta();
    }
    
    // ...
    for(vector<MetaData>::const_iterator i = metaDataContainer.begin(),
            end = metaDataContainer.end();
        i != end; ++i)
    {
        stuff.push_back((*(derivedTypeBuilders[*i]))());
    }
    

    等等

    请不要忘记考虑meta的值不在map中的情况!

    对于特定情况,如果您的元数据值很小,您甚至可以消除运行时开销:

    DerivedTypeCreator[] derivedTypeBuilders = {
        &CreateAlpha, // Metadata::A == 0
        &CreateBeta   // Metadata::B == 1
    };
    
    // ...
    stuff.push_back((*(derivedTypeBuilders[(int)*i]))());
    

    -- 但这种方法可能太低级且容易出错。 (希望 C++ 语法允许这样的初始化。)

    【讨论】:

      【解决方案3】:
      template<class T> Base* Creator() { return new T; }
      typedef Base* (*CreateType)();
      typedef std::pair<const MetaData, CreateType> cpair;
      
      cpair mapper [] =
      {
          cpair(MetaA, Creator<A>),
          cpair(MetaB, Creator<B>),
      };
      
      std::map<MetaData, CreateType> typemap(&mapper[0], &mapper[sizeof(mapper)]);
      
      void foo(MetaData m)
      {
          Base* a = typemap[m]();
      }
      

      【讨论】:

      • 地图构造函数的好用法。
      【解决方案4】:

      您在询问工厂模式。你可以用谷歌搜索。为了尽可能多地投入编译时(w.r.t. 运行时),您可能需要添加搜索词using templates

      但是,由于您的“元数据向量”包含运行时的信息,因此您需要一些动态的东西。 enum 并不是一个坏主意——请看这里,例如:http://www.daniweb.com/forums/thread18399.html。 还要注意typedef InstantiatorMap::value_type InstantiatorMapEntryType 末尾的位。使用“枚举”到“成员函数指针”作为工厂的映射。

      【讨论】:

      • 啊,你可能想更新你的问题的标题......如果可能的话。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多