Тест равенства для производных классов в C++ [дубликат]

Мы используем расстояние Левенштейна метод для проверки на дублирующихся клиентов в нашей базе данных. Это работает вполне хорошо.

12
задан Community 23 May 2017 в 12:15
поделиться

5 ответов

Я помню, как читал краткое описание идиомы публично-не-виртуальный / непублично-виртуальный и ее преимуществ, но не где. У этой викибука хорошее описание.

Вот как вы применяете его к op ==:

struct A {
  virtual ~A() {}

  int a;

  friend
  bool operator==(A const& lhs, A const& rhs) {
    return lhs.equal_to(rhs);
  }
  // http://en.wikipedia.org/wiki/Barton-Nackman_trick
  // used in a simplified form here

protected:
  virtual bool equal_to(A const& other) const {
    return a == other.a;
  }
};

struct B : A {
  int b;

protected:
  virtual bool equal_to(A const& other) const {
    if (B const* p = dynamic_cast<B const*>(&other)) {
      return A::equal_to(other) && b == p->b;
    }
    else {
      return false;
    }
  }
};

struct C : A {
  int c;

protected:
  virtual bool equal_to(A const& other) const {
    if (C const* p = dynamic_cast<C const*>(&other)) {
      return A::equal_to(other) && c == p->c;
    }
    else {
      return false;
    }
  }
};
14
ответ дан 2 December 2019 в 19:54
поделиться

Один из способов сделать это - использовать виртуальный оператор == , который принимает объект базового класса в качестве параметра, чтобы он правильно работал с различными производными объектами. Однако вам нужно сделать эту функцию чисто виртуальной, чтобы заставить все производные объекты реализовать ее. Таким образом, вы не сможете создать экземпляр базового класса. Например:

class A
{
public:
    virtual ~A(){}

    //A virtual operator for comparison
    virtual bool operator==(const A& a) = 0;

protected:
    bool compareBase(const A& a);

private:
    int m_data;
};

bool A::compareBase(const A &a)
{
    return m_data == a.m_data;
}

class B1 : public A
{
public:

    //Override the base class
    bool operator==(const A& a);

private:
    bool compare(const B1* pB)
    {
        if(compareBase(*pB))
        {
            //Code for compare
            return true;
        }

        return false;
    }
};

bool B1::operator ==(const A &a)
{
    //Make sure that the passed type is same
    const B1* pB = dynamic_cast<const B1*>(&a);
    if(pB )
    {
        return compare(pB);
    }

    return false;
}
//Similarly implement for B2
1
ответ дан 2 December 2019 в 19:54
поделиться

Могут ли разные производные классы создавать одинаковые объекты?

Если так: двойная отправка - это вариант: он требует перегрузки в базовом классе , поэтому у вас будут зависимости

В противном случае: решение находится в операторе == (), чтобы проверить typeid и вернуть false, если они разные. В противном случае вызовите частную функцию equal (), в которой производный класс может выполнять static_cast и сравнивать.

2
ответ дан 2 December 2019 в 19:54
поделиться

Если вы не возражаете, что базовый класс ссылается на подклассы, тогда двойная отправка:

#include <iostream>

class B;
class C;

class A
{
public:
    int data;

    virtual bool equals (const A* rhs) const
    {
        std::cout << " A==A ";
        return data == rhs->data;
    }

    virtual bool equals (const B* rhs) const {return false;}
    virtual bool equals (const C* rhs) const {return false;}
};

class B : public A
{
public:
    float some_data;

    virtual bool equals (const A* rhs) const
    {
        return rhs->equals (this);
    }

    virtual bool equals (const B* rhs) const
    {
        std::cout << " B==B ";
        return A::equals (static_cast<const A*> (rhs)) && some_data == rhs->some_data;
    }
};

class C : public A
{
public:
    double more_data;

    virtual bool equals (const A* rhs) const
    {
        return rhs->equals (this);
    }

    virtual bool equals (const C* rhs) const
    {
        std::cout << " C==C ";
        return A::equals (static_cast<const A*> (rhs)) && more_data == rhs->more_data;
    }
};

bool operator== (const A& lhs, const A& rhs)
{
    return lhs.equals (&rhs);
}

int main (int argc, char* argv[])
{

    A* one = new B;
    A* two = new B;
    A* three = new C;

    std::cout << (*one == *one) << std::endl;
    std::cout << (*one == *two) << std::endl;
    std::cout << (*one == *three) << std::endl;
    std::cout << (*three == *three) << std::endl;

    return 0;
}

Делает это без необходимости dynamic_cast.

0
ответ дан 2 December 2019 в 19:54
поделиться

Не беспокойтесь. Тетя Гугл нашла его для меня

chflags -R nouchg .

Из комментариев здесь :

Если вы меняете рабочие области в OS X и вы импортируете проект на основе SVN в ваше новое рабочее пространство, некоторые из ваших файлы могут иметь установленный флаг uchg. SubClipse / SVN не сможет обновить этот проект. Вы получите ошибка:

svn: не удается переименовать файл

каждый раз, когда вы пытаетесь вызвать svn. если ты проблема:

chflags -R nouchg.

на верхнем уровне проекта каталог, это очистит эти флаги

В противном случае вам нужно реализовать некоторые компараторы с большим количеством dynamic_cast <> --ing, чтобы действительно делать это правильно. В качестве альтернативы вы можете реализовать функцию для создания хэш-кода для каждого объекта и использовать его, например

class A {
    public: int data;

    virtual long getHashCode() const {
        // compute something here for object type A
    }

    // virtual here just in case you need to overload it in B or C
    virtual bool equals( const A& obj ) const {
        return (typeid(*this) == typeid(obj) &&
                getHashCode() == obj->getHashCode());
    }
};

class B : public A {
    public: float more_data; bool something_else;

    virtual long getHashCode() const {
        // compute something here for object type B
    }
};

class C : public A {
    public: double more_data;

    virtual long getHashCode() const {
        // compute something here for object type C
    }
};

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

0
ответ дан 2 December 2019 в 19:54
поделиться
Другие вопросы по тегам:

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