Jump to content
  • Advertisement
Sign in to follow this  
gretty

Storing a pointer to an objects member variable

This topic is 2575 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello

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 would 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, nPrices };
foodCol.store( f );
}

// Note storing an ACTUAL object is possible with this class
Collection

system("PAUSE");
return 0;
}


Share this post


Link to post
Share on other sites
Advertisement
C++ does have member variable pointers, but they're not used that often, and in any case they're not how you'd typically solve a problem of this sort.

I only glanced over the code, but I'll go ahead and mention that the typical solution is to use a sorting function such as std::sort(), and either implement the < operator for the type in question, or implement a custom comparator. (You'll want to use the latter method if the objects are stored by pointer or smart pointer; also, using a custom comparator is arguably more clear, since overloading the < operator for objects that wouldn't normally be 'less-than comparable' can be a little confusing.)

Share this post


Link to post
Share on other sites
What if I store the member variable reference like this

dataType Object::** memberVariable;


#include <iostream>
#include <map>
#include <string>

using namespace std;

template <typename Object, typename dataType>
class Collection
{
public:

Collection( dataType Object::*nMemberVariable )
{
memberVariable = nMemberVariable;
}

bool store( const 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*, string> 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, nPrices };
//FoodItem f = {i, nNames, nPrices };
foodCol.store( &f );
}

system("PAUSE");
return 0;
}


Share this post


Link to post
Share on other sites
Not sure if i understood but you could use inheritance and base all objects on a base class with that member? Like make the container take in a pointer to an object of type ContainsMyWeirdSortingVariable

Share this post


Link to post
Share on other sites

Hello

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.

With a little coaxing, std::set will do this:


#include <set>
#include <functional>
#include <string>
#include <iostream>

// This can be reused for any member variable type
template<typename T, typename MemberType>
struct memvar_compare : public std::binary_function<T, T, bool>
{
const MemberType T::*memvar_ptr;
memvar_compare(const MemberType T::* memvar_ptr) : memvar_ptr(memvar_ptr) { }
bool operator() (const T &lhs, const T &rhs) const
{
return (lhs.*memvar_ptr) < (rhs.*memvar_ptr);
}
};

struct person
{
person(const std::string &name, unsigned age) : name(name), age(age) { }

std::string name;
unsigned age;
};

int main()
{
typedef memvar_compare<person, std::string> person_compare;
std::set<person, person_compare> people(&person::name);

//typedef memvar_compare<person, unsigned> person_compare;
//std::set<person, person_compare> people(&person::age);

people.insert(person("Mozart", 35));
people.insert(person("Gandhi", 78));
people.insert(person("Xerces I", 54));
people.insert(person("Me", 29)); // delusions of grandure :)

for (std::set<person, person_compare>::const_iterator it = people.begin(), e = people.end(); it != e; ++it)
std::cout << it->name << ", age " << it->age << '\n';

return 0;
}

Share this post


Link to post
Share on other sites
Also std::map<key, value> will hold them already sorted by key. You can then transverse it backwards.

Share this post


Link to post
Share on other sites
Just to reiterate jyk's advice, as crowbarring the use of a particular container in order to get this behaviour seems a bit daft:

[source lang="c++"]
struct FoodItem
{
FoodItem(unsigned int ID,string name,double price) : ID(ID),name(name),price(price) { }

unsigned int ID;
string name;
double price;
};

bool Less(const FoodItem &a,const FoodItem &b)
{
return a.ID<b.ID;
}

void f()
{
std::vector<FoodItem> items; // or pretty much any other standard container you want

items.push_back(FoodItem(10,"chips",12.3));
items.push_back(FoodItem(5,"bread",14.3));

std::sort(items.begin(),items.end(),Less);
}
[/source]

While a std::map would actually insert the items in sorted order, as owl points out, the additional overhead of storing such small POD types in a map would almost certainly vastly outweigh this benefit.

Also, since when did this work? Have I missed something?

[source lang="c++"]
FoodItem *f = new FoodItem() { i, nNames, nPrices };
[/source]

Share this post


Link to post
Share on other sites
It still sounds like you want a database. Have you considered such a solution?

What are your requirements if the value of the member changes over time?



Also, since when did this work? Have I missed something?

FoodItem *f = new FoodItem() { i, nNames, nPrices };

[/quote]
Looks like a C++0x initialiser list.

Share this post


Link to post
Share on other sites

It still sounds like you want a database. Have you considered such a solution?

What are your requirements if the value of the member changes over time?



Also, since when did this work? Have I missed something?

FoodItem *f = new FoodItem() { i, nNames, nPrices };


Looks like a C++0x initialiser list.
[/quote]

Thanks for everyones replies.

Yes a database would be best but I am using Mosync(Cross Platform Mobile API) & it has limitations. These limitations being, no SQL support (I can write it myself but I dont have time, it does have XML support tho), no STL support (it has its own Set, Queue, Stack, Vector & Maps tho), no threading & doesn't support C++ exceptions.

So to me the best alternative would be a templated container that can be arranged by an object's specific data member (I thought this was a pretty smart way to do this; write it once then use it in many apps). I will look into using the MAUtil::Set class for this tho.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!