Как сравнить два объекта (вызывающий объект и параметр) в классе?

Я пишу класс «Дата» для задания, и у меня возникают проблемы с выполнением одной из функций.

Это заголовочный файл класса.

class Date
{
public:
Date();                                  // Constructor without parameters
Date(int m, int d, int y); // Constructor with parameters.

// accessors
int GetMonth();               // returns the size of the diamond
int GetDay();
int GetYear();

// mutators
bool Set(int m, int d, int y);
bool SetFormat(char f);

// standard input and output routines
void Input();             
void Show();              
void Increment(int numDays = 1);                 
int Compare(const Date& d);     

private:
int month,                    // month variables
    day,                 // day variable
    year;               // year variable
char format;
};

Функция-член, которую я пытаюсь создать, — это функция int Compare(const Date& d). Мне нужна эта функция для сравнения двух объектов Date (вызывающий объект и параметр) и должна возвращать: -1, если вызывающий объект идет первым в хронологическом порядке, 0, если объекты имеют одну и ту же дату, и 1, если объект параметра идет первым в хронологическом порядке. .

Я попытался сделать простой оператор if с оператором ==, но получаю ошибки.

  if (d1 == d2)
     cout << "The dates are the same";
     return (0);

После создания объектов функция должна вызываться следующим образом: d1.Compare(d2)

Заранее спасибо!


person n-2r7    schedule 03.02.2010    source источник


Ответы (7)


int Date :: Compare (const Date& d) {

   if (year<d.year) {
      return -1;
   }
   else if (year>d.year) {
      return 1;
   }
   else if (month<d.month) {
      return -1;
   }
   else if (month>d.month) {
      return 1;
   }
   // same for day

   return 0;
}

Обычно вы также захотите предоставить, например, перегруженные операторы сравнения (также в определении класса):

bool operator == (const Date& d) const {
   return !Compare(d);
}

bool operator < (const Date& d) const {
  return Compare(d)<0;   
}

... // consider using boost::operators

PS: есть более умные реализации Compare() - просто проверьте другие ответы. Это довольно просто и читабельно, но точно соответствует вашей спецификации.

person Alexander Gessler    schedule 03.02.2010
comment
Спасибо, это именно то, что я пытался сделать. - person n-2r7; 03.02.2010

Вот как я мог бы реализовать вашу функцию сравнения, хотя формат требует времени, чтобы привыкнуть к нему:

int Date::Compare(const Date& d) const {
  return
    (year < d.year)   ? -1 :
    (year > d.year)   ?  1 :
    (month < d.month) ? -1 :
    (month > d.month) ?  1 :
    (day < d.day)     ? -1 :
    (day > d.day)     ?  1 :
                         0;
}

Или, возможно:

template<typename T>
int Compare(T a, T b) {
    if (a < b) return -1;
    if (b < a) return 1;
    return 0;
}

int Date::Compare(const Date& d) const {
    int a = Compare(year, d.year);
    if (a == 0) a = Compare(month, d.month);
    if (a == 0) a = Compare(day, d.day);
    return a;
}

Я бы не стал использовать operator== в Compare, хотя ответы, говорящие вам, как реализовать operator==, подойдут, если вы тоже этого хотите. Причина в том, что operator== явно придется просматривать те же поля, что и сравнение, и если оно вернет false, то Compare снова проделает очень похожую работу. Эффективность, вероятно, не проблема, но она дублирует логику.

И что бы ни стоило, идиоматический C++ должен реализовать operator< и, возможно, также согласованные operator== и operator>, а не универсальную функцию сравнения. Операторы — это то, что стандартные алгоритмы используют для поиска и сортировки, а все остальное следует за ними. Java решила поступить по-другому.

person Steve Jessop    schedule 03.02.2010
comment
Спасибо, это отличное объяснение. - person n-2r7; 03.02.2010

в public область класса

bool operator==(const Date& rhs) const {
    return
       year == rhs.year
       && month == rhs.month
       && day == rhs.day
    ;
}
person Notinlist    schedule 03.02.2010
comment
Обратите внимание, что метод является константой. Ваш метод Compare() (и другие) также должен быть константным. Если бы ваш Compare() был бы const, я мог бы вызвать его из оператора ==() :-) - person Notinlist; 03.02.2010

Сравните объект по содержимому, т.е. в вашем случае даты равны дню, месяцу и году (а возможно и format - в зависимости от вашей семантики).

Кроме того, C++ уже включает в себя отличное средство для сравнения объектов: operator ==, которое позволяет писать более понятный код, чем вызов метода Compare.

Кстати, позаботьтесь об этом:

  if (d1 == d2)
     cout << "The dates are the same";
     return (0);

Если условие истинно, будет выполнена строка cout. return будет выполнено, даже если условие ложно.

person Eli Bendersky    schedule 03.02.2010

Семантика || в С++ делает это немного загроможденным:

static inline int cmp(int a, int b)
{
  return a < b ? -1 : a == b ? 0 : 1;
}

int Date::Compare(const Date& d)
{
  int result;
  (result = cmp(year, d.year))     ||
    (result = cmp(month, d.month)) ||
      (result = cmp(day, d.day));

  return result;
}
person Greg Bacon    schedule 03.02.2010
comment
Но если вам действительно нужно начинать имя со знака подчеркивания, убедитесь, что оно не находится в глобальном пространстве имен — это не разрешено. - person Mike Seymour; 04.02.2010

Чтобы использовать оператор == для пользовательских типов, вы должны его реализовать. Кроме того, ваша функция сравнения должна быть помечена как константная функция-член:

class Date
{
...
int Compare(const Date& d) const;     

bool operator==(const Date& rhs) const
{
    return 0 == Compare(rhs);
}
person John Dibling    schedule 03.02.2010

Вы не можете сделать d1 === d2, потому что я считаю, что он сравнивает адреса памяти (давно не делал C++).

Что вам нужно сделать, так это написать функцию, которая будет сравнивать каждый член вашего класса Date и возвращать отрицательное число, 0 или положительное число. Отрицательный означает меньше, 0 означает то же самое, а положительный означает больше.

Например, в Java:

public int compareTo(Date date) {
  int returnValue = 0;

   returnValue = this.getYear() - date.getYear();

   if(returnValue == 0) {
      returnValue = this.getMonth() - date.getMonth();

      if(returnValue == 0) {
         returnValue = this.getDay() - date.getDay();
      }
   }
}
person Vivin Paliath    schedule 03.02.2010
comment
d1 == d2 не компилируется, если операция не реализована где-то. В данном случае это не реализовано. - person John Dibling; 03.02.2010
comment
В OP явно указано... функция должна вызываться так d1.Compare(d2), что означает, что ни d1, ни d2 не являются адресами памяти (указателями). Сравнение адресов памяти в этом случае повлечет за собой что-то вроде &d1 == &d2, а не d1 == d2. Создание оператора равенства, подобного опубликованному @Notinlist, обеспечивает желаемую семантику d1 == d2. - person Void; 03.02.2010
comment
Спасибо за этот указатель, я не думал об этом. - person n-2r7; 03.02.2010
comment
@Void А, хорошая мысль. Как я уже сказал, я давно не занимался C++. Я был в Java-стране, где все является ссылкой/указателем :) - person Vivin Paliath; 03.02.2010
comment
Эта реализация compareTo не является хорошей общей стратегией из-за переполнения. Очевидно, что даты не будут переполняться, так что вам это может сойти с рук, но подумайте, если this.getYear() равно INT_MAX, а date.getYear() равно -1. Тогда LHS › RHS, но LHS - RHS ‹ 0. - person Steve Jessop; 03.02.2010
comment
Надеюсь, есть функция проверки, которая гарантирует, что атрибут года не равен INT_MAX. Но да, это, вероятно, не очень хорошая стратегия. - person Vivin Paliath; 03.02.2010
comment
Да, это нормально для свиданий, если ваши свидания не заходят слишком далеко в будущее. - person Steve Jessop; 05.02.2010