Как вставить объект в структуру карты по определенному полю? - PullRequest
0 голосов
/ 02 сентября 2010

У меня есть объект - Сотрудник, и я хочу знать, как вставить этот объект в структуру карты, отсортированную по полю char * lastName.Thanx.Моя карта должна содержать указатели на объекты Employee, а не сами объекты.ключ - фамилия сотрудника, карта должна быть отсортирована по фамилии сотрудников, должен ли я использовать мультикарту?

Ответы [ 5 ]

2 голосов
/ 02 сентября 2010

Итак, у вас есть std :: map с пользовательской функцией компаратора (вы перегрузили оператор less чем) и хотите вставить объекты так, чтобы они были в правильном порядке?

myMap.insert( make_pair( myKey, myEmployee ) );

где myKey - ключ к вашей карте.Однако по звучанию вашего вопроса на самом деле звучит так, будто вы используете объект в качестве своего собственного ключа.В этом случае просто используйте std :: set и

mySet.insert( myEmployee );

. Я бы также предложил, чтобы вы не использовали char* в качестве средства хранения lastName и предпочитали std :: string.

РЕДАКТИРОВАТЬ:

После комментариев ниже, вы должны быть в состоянии передать const char* в другую функцию?Если это так, все равно используйте string, поскольку он имеет хороший метод .c_str() специально для устаревшей совместимости.Его можно использовать так:

void stuffHappens(const char* _input){
    //magic happens in here
}

stuffHappens( myString.c_str() );

и вуаля, вы намного безопаснее!

1 голос
/ 02 сентября 2010

Как написал в своих комментариях Филипп Поттер, вы должны определенно использовать std::string. Потому что два разных char*, объявленных в нескольких местах / файлах в вашем cpp-коде НЕ БУДУТ , имеют одинаковые адреса! Поскольку char * - это не что иное, как целое число, у вас будет несколько символов char * для одной и только одной и той же фамилии, и это не то, что вам нужно.

иди сюда:

std::map<std::string,YourType> yourMap;
std::string strMyLastName = "Rolland";
YourType aValue;
yourMap[strMyLastName ] = aValue;
1 голос
/ 02 сентября 2010

Чтобы добавить к тому, что сказал, если объект Employee содержит свой собственный ключ, вам, вероятно, следует использовать set.Чтобы использовать этот набор, вам необходимо явно определить метод сравнения для объекта Employee.Есть два способа сделать это: либо определить оператор <для объекта: </p>

class Employee
{
public:
  bool operator<(const Employee &rhs)
  {
    return strcmp(lastName, rhs.lastName) < 0;
  }
...
};

Или вы можете определить функтор, который вы указываете набору для использования:

struct EmployeeLessThan
{
  bool operator()(const Employee &lhs, const Employee &rhs)
  {
    return strcmp(lhs.lastName, rhs.lastName) < 0;
  }
};

std::set<Employee, EmployeeLessThan> myEmployees;

Изменить: Одна очень важная вещь, которую нужно иметь в виду, это то, что set хранит все свои предметы как const.Это происходит потому, что изменение элемента в set может изменить порядок элементов, а set не может обнаружить это и изменить порядок.Это может быть проблематично, если вы хотите обновить любого из сотрудников, содержащихся в наборе.Лучший способ обойти эту проблему - объявить любой элемент данных Employee, который вы можете захотеть изменить, как mutable.Это позволит вам изменять их значения, даже когда оно const.

Edit2: если вы решите продолжить использовать карту, а ключ - char *, имейте в виду, что по умолчанию карта собираетсясравнить два char * s по значению их указателя, а не по строке, на которую они указывают.В этом случае лучше всего использовать std::string вместо char *.Кроме того, вы можете определить функтор для передачи на карту:

struct CharStarLessThan
{
  bool operator()(const char *lhs, const char *rhs)
  {
    return strcmp(lhs, rhs) < 0;
  }
};

std::map<char *, Employee, CharStarLessThan> myEmployees;
1 голос
/ 02 сентября 2010

Вы можете создать «функтор», который переопределяет operator(), принимая ссылки на два ваших объекта и возвращая логическое значение obj1 < obj2.

Например:

class EmployeeComparator
{
    public:
    bool operator()(const Employee& emp1, const Employee& emp2)
    {
        return strcmp(emp1.lastName, emp2.lastName) < 0;
    }
}

Когда вы создаете свою std :: map, вы передаете EmployeeComparator в качестве объекта сравнения, например:

std::map<Employee, T, EmployeeComparator> m;

Идеи других авторов по поводу переопределения оператора < также будут работать, но с помощью этого метода вы должны выбрать один критерий для сортировки. С моей точки зрения, у вас может быть одна карта, которая сортирует по фамилии, другая - по идентификатору сотрудника и т. Д. С каждой картой вы будете передавать свой функтор в качестве сортировщика.

Имейте в виду, что, с моей точки зрения, если вы пытаетесь отсортировать по частному полю, объявите свой функтор сортировки как класс друга для сортировки.

1 голос
/ 02 сентября 2010

Определите bool operator <(const Employee& other) для класса Employee.В качестве альтернативы, определите bool operator <(const Employee& left, const Employee& right) как функцию, не являющуюся членом, и установите для friend значение Employee.Преимущество первого подхода заключается в том, что он локальный по отношению к Employee, и это улучшает инкапсуляцию.Преимущество последнего подхода заключается в том, что он будет работать с любыми двумя типами, которые могут быть преобразованы в Employee.В качестве альтернативы вы можете создать функтор сравнения вместо operator <() и передать его конструктору карты.

Наконец, используйте функцию-член insert() из std::map<> для вставки новых сотрудников.std::map<> также определил operator [](), что позволяет вставлять его в карту.Функция insert() не будет вставлять элемент, если элемент уже находится на карте, тогда как operator []() обновит элемент, если он уже существует.

...