Хранение указателя на переменную-член объекта - PullRequest
2 голосов
/ 04 июня 2011

У меня есть проблема, которая раздражала меня некоторое время, и я еще не нашел решение. Я хотел бы создать контейнерный класс, который хранит объекты и сортирует их в соответствии с ОДНОЙ из значений их переменных-членов. Поэтому, если у меня есть класс студентов (с переменной члена int studentID), я хочу сохранить их в своем классе Container в соответствии с их значением studentID в порядке возрастания. Я сделал контейнерный класс шаблонным классом, чтобы я мог использовать его в любом своем проекте.

Моя проблема с моим классом Container: Я не могу хранить указатели объектов (например, объектов Student). Точнее, проблема в том, что я не могу сохранить ссылку (?) На переменную-член объекта (например, ссылку / указатель на переменную studentID Студента). Эта проблема раздражала меня целую вечность, и любая информация или советы будут высоко оценены. Есть ли способ сделать мой указатель класса контейнера ниже указателей на переменные-члены объектов? Есть ли другой способ создания контейнера объектов, который можно отсортировать по переменным-членам?

#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;   
}

Ответы [ 2 ]

1 голос
/ 04 июня 2011

Если я правильно понимаю вопрос, то, что вы спросили, кажется set.std::set может принять предикат для сортировки в качестве второго аргумента шаблона.Если вы подготовите предикат, который сравнивает целевой элемент для сортировки, элементы в set будут отсортированы по этому элементу.
Например:

#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 );
}

Вот тест для ideone .

0 голосов
/ 04 июня 2011

Во-первых, ваш Collection настроен на два типа: Object и dataType.Тем не менее, вы всегда заполняете только первое, как Collection <FoodItem*> foodCol(...).Измените это тоже:

Collection <FoodItem*,string> foodCol(&FoodItem::name);

Далее,

FoodItem f( 1, "a", 4 );
foodCol.store( f );

не должно компилироваться.Вы ожидаете Object*, в то время как Object - это FoodItem*, так что в итоге вы ожидаете FoodItem**, но то, что вы передаете, - это просто FoodItem.Измените определение store, чтобы просто взять const Object& и передать его &f в приведенном выше примере.Поскольку Object равен FoodItem*, ваш store будет ожидать FoodItem* const&, то есть постоянную ссылку на указатель FoodItem*.Именно то, что мы хотим.

Все остальное выглядит хорошо, насколько я вижу, особенно указатель на данные члена корректен.Но я могу что-то упустить из виду, уже очень поздно ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...