Storing a pointer to an objects member variable
I have a problem that has been annoying me for a while & I have yet to come up with a solution. I would like to create a container class that stores objects & sorts them according to ONE of their member variable values. So if I have a class of Students (with the member variable int studentID), I want to store them in my Container class according to their studentID value in ascending order. I have made the container class a templated class so I can use for any class in any of my projects.
My problem with my Container class: I cannot store pointers of objects(for example Student objects). The problem more precisely is that I cannot store a reference(?) to an objects member variable (for example a reference/pointer to a Student's studentID variable).
This problem has been annoying me for ages & any information or advice w开发者_如何学编程ould be highly appreciated. Is there a way to make my below Container class store pointers to objects member variables? Is there a different way to create a container of objects that can be sorted by their member variables?
#include <iostream>
using namespace std;
template <typename Object, typename dataType>
class Collection
{
public:
Collection( dataType Object::*nMemberVariable )
{
memberVariable = nMemberVariable;
}
bool store( Object* o )
{
// check that o is not a NULL pointer & not already present in maps
if ( o==NULL || instanceVarMap.find(o->*memberVariable) != instanceVarMap.end() )
{
return false;
}
instanceVarMap.insert( o->*memberVariable, o );
return true;
}
private:
dataType Object::* memberVariable;
std::map <dataType, Object*> instanceVarMap;
};
struct FoodItem
{
unsigned int ID;
string name;
double price;
};
int main()
{
// I am attempting to store a pointer to an objects member variable
// this is so I can create a custom container class(like a map or vector) that
// sorts its contents (which are FoodItem objects) according to their member variable values
// so a container could sort all its elements according to a FoodItems ID value or name value
Collection <FoodItem*> foodCol( &FoodItem::name );
string nNames[] = {"a", "b", "c", "d"};
double nPrices[] = {1.1, 2.2, 3.3, 4.4};
for (int i=0; i<4; i++)
{
FoodItem *f = new FoodItem() { i, nNames[i], nPrices[i] };
foodCol.store( f );
}
// Note storing an ACTUAL object is possible with this class
Collection <FoodItem*> foodCol( &FoodItem::name );
FoodItem f( 1, "a", 4 );
foodCol.store( f );
system("PAUSE");
return 0;
}
If I understand the question correctly, what you asked seems a set
.
std::set
can take a predicate for sorting as the second template argument.
If you prepare a predicate which compares the target member for sorting,
the elements in the set
will be sorted according to that member.
For example:
#include <set>
struct FoodItem {
unsigned int ID;
double price;
};
template< class C, class T, T C::* M >
struct member_comparator { // predicate
bool operator()( C const* x, C const* y ) const { return x->*M < y->*M; }
};
int main() {
FoodItem a = { 1, 2.5 }, b = { 2, 1.5 };
// a set sorted by ID
std::set< FoodItem*
, member_comparator< FoodItem, unsigned, &FoodItem::ID > > s_ID;
s_ID.insert( &a );
s_ID.insert( &b );
// a set sorted by price
std::set< FoodItem*
, member_comparator< FoodItem, double, &FoodItem::price > > s_price;
s_price.insert( &a );
s_price.insert( &b );
}
Here is a test on ideone.
First, your Collection
is templated on two types: Object
and dataType
. However, you always only fill in the first like Collection <FoodItem*> foodCol(...)
. Change that too:
Collection <FoodItem*,string> foodCol(&FoodItem::name);
Next,
FoodItem f( 1, "a", 4 );
foodCol.store( f );
shouldn't compile. You're expecting an Object*
, while Object
is a FoodItem*
, so in the end you're expecting a FoodItem**
, but what you pass is a simple FoodItem
. Change the definition of store
so it simply takes a const Object&
and pass it &f
in the above example. Since Object
is FoodItem*
, your store
will expect a FoodItem* const&
, that is, a constant reference to a FoodItem*
pointer. Exactly what we want.
The rest looks fine as far as I can see, especially the member data pointer is correct. But I might be overlooking something, it's very late here...
精彩评论