Reputation: 11012
I'm working on a really badly designed project, and I've stumbled upon this data structure :
class OldBagOfData
{
public:
std::vector< BaseClass* > baseDatas;
std::vector< Derived1* > derived1Datas;
std::vector< Derived2* > derived2Datas;
std::vector< Derived3* > derived3Datas;
std::vector< Derived4* > derived4Datas;
}
The method to update the class is using a awful lot of if/else conditionals (several dozens) and the members are modifiables (on top of that it is using pointers instead of instances) even though we are only reading the datas.
I've already simplified the code by using generic functions and template :
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") */
}
However, since I'm only reading datas and queuing new input , I would like to use iterators :
// 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 */
}
How can I create std::vector::iteratorDerivedX ? Any other advices on my design is welcomed.
Upvotes: 0
Views: 205
Reputation: 11012
I've found a method using templated iterator. Unfortunately it add a lot of overhead so I am not sure I will use it :
#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;
}
}
Upvotes: 0
Reputation: 10069
You can't (as far as I know) add a new member to the std::vector
class. You could, however, subclass it, so you could define your own iterators.
On the other hand, you could add some new methods to your CustomBagOfData
class, something like:
public:
std::vector<Derived1*>::iterator getDerived1Begin() {
return getDerived1Datas().begin()
}
// And the same for getDerived1End
However, despite not knowing how DefinedN
classes are implemented, I'd suggest getting rid of those magic numbers (Derived1, Derived2, ...) and doing something more elegant with parameters.
Upvotes: 0
Reputation: 946
you can hold the return of the function call before the for loop;
Also, you are calling the end() method every iteration, which can be expensive.
And for iterators, pos increment is more expensive than pre incrementors.
std::vector<Derived1*> tmp = obod.getDerived1Datas();
for( std::vector<Derived1*>::iterator it = tmp.begin(), ed = tmp.end(); it != ed; ++i)
{
/* processing *it */
}
Upvotes: 1