如何创建特定的std :: vector迭代器?

时间:2013-04-04 11:08:05

标签: c++ templates vector iterator

我正在设计一个设计非常糟糕的项目,我偶然发现了这个数据结构:

class OldBagOfData 
{
public:
    std::vector< BaseClass* > baseDatas;
    std::vector< Derived1* > derived1Datas;
    std::vector< Derived2* > derived2Datas;
    std::vector< Derived3* > derived3Datas;
    std::vector< Derived4* > derived4Datas;

}

更新类的方法是使用大量的if / else条件(几十个),并且成员是可修改的(最重要的是它使用指针而不是实例),即使我们只是读取数据。

我已经使用通用函数和模板简化了代码:

class CurrentBagOfData 
{
private:
    std::vector< BaseClass* > genericContainer;

    Template< typename DataType>
    std::vector< DataType* > getData( datatype IDtype);

public:
    std::vector< BaseClass* > getbaseDatas(); /* = getData<Base>("base") */
    std::vector< Derived1* > getDerived1Datas(); /* = getData<Derived1>("derived1") */
    std::vector< Derived2* > getDerived2Datas(); /* = getData<Derived2>("derived2") */
    std::vector< Derived3* > getDerived3Datas(); /* = getData<Derived3>("derived3") */
    std::vector< Derived4* > getDerived4Datas(); /* = getData<Derived4>("derived4") */

}

但是,由于我只是在读取数据并排队新输入,所以我想使用迭代器:

// This loop is forbidden because obod.getDerived1Datas() is a temporary object
for( std::vector<Derived1*>::iterator it = obod.getDerived1Datas().begin();
                                         it != obod.getDerived1Datas().end(); i++)
{
  /* processing *it */
}

//What I want to do :
for( std::vector<Derived1*>::iteratorDerived1 it = obod.begin(); it != obod.end(); i++)
{
  // it iterate over every Derived1 datas in the generic container
  /* processing *it */
}

如何创建std :: vector :: iteratorDerivedX?欢迎使用我设计的任何其他建议。

3 个答案:

答案 0 :(得分:1)

你可以在for循环之前保持函数调用的返回;

此外,您每次迭代都会调用end()方法,这可能很昂贵。

对于迭代器,pos增量比前增量器更昂贵。

std::vector<Derived1*> tmp = obod.getDerived1Datas();
for( std::vector<Derived1*>::iterator it = tmp.begin(), ed = tmp.end(); it != ed; ++i)
{
  /* processing *it */
}

答案 1 :(得分:0)

你不能(据我所知)在std::vector课程中添加新成员。但是,您可以将其子类化,因此您可以定义自己的迭代器。

另一方面,您可以为CustomBagOfData课程添加一些新方法,例如:

public:
    std::vector<Derived1*>::iterator getDerived1Begin() { 
        return getDerived1Datas().begin()
    }
    // And the same for getDerived1End

然而,尽管不知道如何实现DefinedN类,我建议摆脱那些神奇的数字(Derived1,Derived2,......)并用参数做更优雅的事情。

答案 2 :(得分:0)

我找到了一个使用模板化迭代器的方法。不幸的是它增加了很多开销,所以我不确定我会用它:

#include <iostream>
#include <vector>

typedef std::string datatype ;

class BaseClass{
public:
    BaseClass():type("base"){}
    datatype type;

};

class Derived1 : public BaseClass{
public:
    Derived1(){ type= "derived1"; }
};
class Derived2 : public BaseClass{
public:
    Derived2(){ type ="derived2"; }
};
class Derived3 : public BaseClass{
public:
    Derived3(){ type ="derived3"; }
};
class Derived4 : public BaseClass{
public:
    Derived4(){ type ="derived4"; }
};


class CurrentBagOfData 
{
private:


    template< typename DataType>
    std::vector< DataType* > getData( datatype IDtype)
    {
        std::vector< DataType* > output;
        for(int i=0; i< genericContainer.size(); i++)
        {
            if(genericContainer[i]->type == IDtype)
            {
                output.push_back( (DataType*) genericContainer[i]);
            }

        }
        return output;
    }

public:

    // Begin of the specialized container
    template< class DataType>
    std::vector< BaseClass* >::iterator begin()
    {
        std::vector< BaseClass* >::iterator it = genericContainer.begin();


        datatype type = DataType().type;
        while( it != genericContainer.end() && (*it)->type != type   )
        {
            it++;
        }

        return it;

    }

    // End of the specialized container
    template< class DataType>
    std::vector< BaseClass* >::iterator end()
    {
        std::vector< BaseClass* >::iterator it = genericContainer.begin();
        std::vector< BaseClass* >::iterator output = it;

        datatype type = DataType().type;
        while( it!= genericContainer.end() )
        {
            it++;


            if( it!= genericContainer.end() && (*it)->type == type )
            {

                output = it;
            }

        }



        return output;

    }


    // Iterate over a certain type of elements in the container
    template< class DataType>
    void gen( std::vector<BaseClass*>::iterator &it)
    {
        const std::vector< BaseClass* >::iterator e =  this->genericContainer.end();

        // Mandatory increment
        if(it!= e )
            it++;

        // Loop until next DataType elem
        datatype type = DataType().type;
        while( it!= e && (*it)->type != type   )
        {
            it++;
        }

    }


    std::vector< BaseClass* > getbaseDatas(){ return getData<BaseClass>("base"); }
    std::vector< Derived1* > getDerived1Datas(){ return getData<Derived1>("derived1"); }
    std::vector< Derived2* > getDerived2Datas(){ return getData<Derived2>("derived2"); }
    std::vector< Derived3* > getDerived3Datas(){ return getData<Derived3>("derived3"); }
    std::vector< Derived4* > getDerived4Datas(){ return getData<Derived4>("derived4"); }


    std::vector< BaseClass* > genericContainer;






};



int main()
{
    // Object
    CurrentBagOfData cbod;

    cbod.genericContainer.push_back(new(BaseClass));
    cbod.genericContainer.push_back(new(Derived1));
    cbod.genericContainer.push_back(new(Derived3));
    cbod.genericContainer.push_back(new(Derived2));
    cbod.genericContainer.push_back(new(Derived1));
    cbod.genericContainer.push_back(new(Derived4));
    cbod.genericContainer.push_back(new(Derived3));
    cbod.genericContainer.push_back(new(Derived3));

    // Loop on Derived4 object, using the original method
    std::vector< Derived4* > o = cbod.getDerived4Datas();
    for (int i=0; i < o.size(); i++ )
    {
        std::cout << o[i]->type << std::endl;
    }
    std::cout << std::endl;

    // Loop on Derived3 objects, with custom iterators.
    std::vector< BaseClass* >::iterator it;
    for( it = cbod.begin< Derived3 >(); it <= cbod.end< Derived3 >(); cbod.gen< Derived3 >(it) )
    {
        std::cout << (*it)->type << std::endl;
    }

}