Изящное Объектное сравнение

Мы создаем индекс вместе с условием, является ли он duplicated

i1 <- with(fitness_calculations, individual == "nnn/nn/nn/nn" & gen_check ==  2)
i2 <- !duplicated(i1) & i1

fitness_calculations$gen_check[i2] <- 3
fitness_calculations
#    individual gen_check    acc   loss
#1 nnn/nn/nn/nn         3 0.9889 0.0112
#2     nnn/n/nn         2 0.7845 0.3451
#3 nnn/nn/nn/nn         2 0.5640 0.4231

Или другой вариант - заключить в which и извлечь только первый индекс

[111 ]

данные

fitness_calculations <- structure(list(individual = c("nnn/nn/nn/nn",
 "nnn/n/nn", "nnn/nn/nn/nn"
 ), gen_check = c(2L, 2L, 2L), acc = c(0.9889, 0.7845, 0.564), 
loss = c(0.0112, 0.3451, 0.4231)), class = "data.frame", row.names = c("1", 
 "2", "3"))
9
задан mintydog 16 November 2008 в 05:41
поделиться

8 ответов

Это зависит от предполагаемой семантики A, B и C и семантики compare (). Сравнение - это абстрактное понятие, которое не обязательно имеет единственное правильное значение (или вообще какое-либо значение, если на то пошло). На этот вопрос нет единственного правильного ответа.

Вот два сценария, в которых сравнение означает две совершенно разные вещи с одной и той же иерархией классов:

class Object 
{
    virtual int compare(const Object& ) = 0;
    float volume;
};

class Animal : Object 
{
    virtual int compare(const Object& );
    float age;
};

class Zebra  : Animal 
{
    int compare(const Object& );
};

Мы можем рассмотреть (по крайней мере) два способа сравнения двух Зебр: которая старше, а какой объем больше? Оба сравнения действительны и легко вычислимы; разница в том, что мы можем использовать объем для сравнения зебры с любым другим объектом, но мы можем использовать возраст только для сравнения зебр с другими животными. Если мы хотим, чтобы compare () реализовал семантику сравнения возраста, не имеет смысла определять compare () в классе Object, поскольку семантика не определена на этом уровне иерархии. Стоит отметить, что ни один из этих сценариев не требует какого-либо преобразования, поскольку семантика определяется на уровне базового класса (будь то Object при сравнении объема или Animal при сравнении возраста).

Это поднимает более важный вопрос. проблема в том, что некоторые классы не подходят для одной универсальной функции compare (). Часто имеет смысл реализовать несколько функций, которые явно указывают, что сравнивается, например compare_age () и compare_volume (). Определение этих функций может происходить в той точке иерархии наследования, где семантика становится актуальной, и адаптировать их к дочерним классам должно быть тривиально (если это вообще необходимо).

1
ответ дан 3 November 2019 в 08:21
поделиться

У меня едва есть эта проблема в C++. В отличие от Java, мы не обязаны наследовать все наши классы от того же класса корневого объекта. При контакте с сопоставимым (/оценивают семантику) классов, она очень вряд ли сделает, чтобы они произошли из полиморфной иерархии.

Если потребность реальна в Вашей конкретной ситуации, Вы вернулись в к double-dispatch/multimethods проблеме. Существуют различные способы решить его (dynamic_cast, таблицы функций для возможных взаимодействий, посетителей...)

0
ответ дан 3 November 2019 в 08:21
поделиться

Если Вы подразумеваете, что Сравнивание () в классе B или C должно всегда передаваться объект класса B или C, независимо от того, что говорит подпись, можно работать с указателями на экземпляры вместо экземпляров и попробовать к удрученному указатель в коде метода с помощью чего-то как

int B::Compare(A *ptr)
{
   other = dynamic_cast <B*> (ptr);
   if(other)
      ...  // Ok, it was a pointer to B
}

(Такая перегрузка была бы необходима только для тех производных классов, которые добавляют к состоянию их родителя что-то, что влияет на сравнение.)

0
ответ дан 3 November 2019 в 08:21
поделиться

Вероятно, я сделал бы это как это:

class A
{
 public:
  virtual int Compare (const A& rhs) const
  {
    // do some comparisons
  }
};

class B
{
 public:
  virtual int Compare (const A& rhs) const
  {
    try
    {
      B& b = dynamic_cast<A&>(rhs)
      if (A::Compare(b) == /* equal */)
      {
        // do some comparisons
      }
      else
        return /* not equal */;
    }
    catch (std::bad_cast&)
    {
      return /* non-equal */
    }
  }
};
1
ответ дан 3 November 2019 в 08:21
поделиться

Сравнивание должно быть отражающим, таким образом:

let a = new A
let b = new B (inherits from A)

if (a.equals(b))
 then b.equals(a) must be true!

Так a.equals(b) должен возвратить false, так как B, вероятно, содержит поля, которые не имеет A, что означает b.equals(a) вероятно, будет ложь.

Таким образом в C++ сравнение должно быть виртуальным, я предполагаю, и необходимо использовать проверку типа, чтобы видеть, что параметр имеет "тот же" тип как текущий объект.

0
ответ дан 3 November 2019 в 08:21
поделиться

В дополнение к dynamic_cast также необходимо передать ссылку или указатель, вероятно, константа, Сравнить функция может также, вероятно, быть константой.

class B: public A
{
    B();
    virtual ~B();
    virtual int Compare(const A &Other) const;
};


int B::Compare(const A &Other) const
{
    const B *other = dynamic_cast <const B*> (&Other);
    if(other) {
        // compare
    }
    else {
        return 0;
    }
}

Править: Должен скомпилировать перед регистрацией...

0
ответ дан 3 November 2019 в 08:21
поделиться

Я реализовал бы его как это:

class A{
    int a;

public:
    virtual int Compare(A *other);
};


class B : A{
    int b;

public:
    /*override*/ int Compare(A *other);
};

int A::Compare(A *other){
    if(!other)
        return 1; /* let's just say that non-null > null */

    if(a > other->a)
        return 1;

    if(a < other->a)
        return -1;

    return 0;
}

int B::Compare(A *other){
    int cmp = A::Compare(other);
    if(cmp)
        return cmp;

    B *b_other = dynamic_cast<B*>(other);
    if(!b_other)
        throw "Must be a B object";

    if(b > b_other->b)
        return 1;

    if(b < b_other->b)
        return -1;

    return 0;
}

Это очень похоже на IComparable шаблон в.NET, которая работает очень хорошо.

Править:

Один протест к вышеупомянутому - это a.Compare(b) (где a A и b B), может возвратить равенство и никогда не будет выдавать исключение, тогда как b.Compare(a) будет. Иногда это - то, что Вы хотите, и иногда это не. Если это не, то Вы, вероятно, не хотите Ваш Compare функция, чтобы быть виртуальными, или Вы хотите выдержать сравнение type_infos в основе Compare функция, как в:

int A::Compare(A *other){
    if(!other)
        return 1; /* let's just say that non-null > null */

    if(typeid(this) != typeid(other))
        throw "Must be the same type";

    if(a > other->a)
        return 1;

    if(a < other->a)
        return -1;

    return 0;
}

Обратите внимание что производные классы Compare функции не должны изменяться, так как они должны назвать базовый класс Compare, где type_info сравнение произойдет. Можно, однако, заменить dynamic_cast в переопределенном Compare функция с a static_cast.

1
ответ дан 3 November 2019 в 08:21
поделиться

Я предложил бы не сделать это виртуальным. Единственный недостаток - то, что явный необходимо сказать, которые выдерживают сравнение с использованием, если классы не являются тем же. Но потому что Вы имеете к, Вы могли бы определить ошибку (во время компиляции), которая иначе могла вызвать ошибку периода выполнения...

class A
{
  public:
    A(){};
    int Compare(A const & Other) {cout << "A::Compare()" << endl; return 0;};
};

class B: public A
{
  public:
    B(){};
    int Compare(B const & Other) {cout << "B::Compare()" << endl; return 0;};
};

class C: public A
{
  public:
    C(){};
    int Compare(C const & Other) {cout << "C::Compare()" << endl; return 0;};
};

int main(int argc, char* argv[])
{
    A a1;
    B b1, b2;
    C c1;

    a1.Compare(b1);     // A::Compare()
    b1.A::Compare(a1);  // A::Compare()
    b1.Compare(b2);     // B::Compare()
    c1.A::Compare(b1);  // A::Compare()

    return 0;
}
0
ответ дан 3 November 2019 в 08:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: