2014-09-26 3 views
0

Я хочу реализовать функцию для сравнения производного класса. Но я обнаружил, что мне нужно подвергнуть объект базового класса производному объекту класса.Как реализовать виртуальную функцию equal()

Есть ли способ избежать использования литых здесь или другого лучшего дизайна для реализации функции сравнения?

class A { 
    public : 
     virtual bool equal(const A & obj) const = 0; 
}; 

class AA : public A{ 
    public: 
     AA (int i) : m_i(i) {} 
     virtual bool equal(const A & obj) const 
     { 
      return m_i == dynamic_cast<const AA&>(obj).m_i; 
     } 

    private: 
     int m_i; 
}; 

int main() { 
    AA aa1(10), aa2(9); 
    A &a1 = aa1, &a2 = aa2; 

    a1.equal(a2); 

    return 0; 
} 
+2

Помните, что 'dynamic_cast' для ссылочного типа может вызывать исключение. Может быть, лучше использовать вместо указателя вместо этого, вы, вероятно, просто хотите вернуть 'false', если указатель возвращается NULL. –

+0

Может быть, используя getter, который является виртуальным в базовом классе для переменной-члена 'm_i'? – abiessu

+0

Подробнее о двойном отправке и о классическом решении для него - образец посетителя. – Ilya

ответ

0

Я был укушен этим запросом много раз в своем собственном коде. Я представлю упрощенный пример:

struct Fruit 
{ 
    virtual bool is_equal(Fruit const & f) const = 0; // Compare two fruits 
    // Some dangerous actions: 
    bool operator==Fruit const & f) 
    { 
    return is_equal(f); // Dispatch! 
    } 
}; 

struct Strawberry : public Fruit 
{ 
    bool is_equal(Fruit const & f) 
    { 
    bool equal = false; 
    // The f could be any fruit, such as tomatoes or pineapples or bananas. 
    // Need to perform a dynamic_cast to verify that the f is a strawberry. 
    Strawberry const & s = dynamic_cast<Strawberry const &>(f); 
    // perform strawberry comparison; 
    return equal; 
    }; 
} 

struct Banana : public Fruit 
{ 
    bool is_equal(Fruit const & f) 
    { 
    bool equal = false; 
    // The f could be any fruit, such as tomatoes or pineapples or strawberries. 
    // Need to perform a dynamic_cast to verify that the f is a banana. 
    Banana const & b = dynamic_cast<Banana const &>(f); 
    // perform banana comparison; 
    return equal; 
    }; 
} 

bool Compare_Fruits(Fruit const * pf1, Fruit const * pf2) 
{ 
    if (*pf1 == *pf2) 
    { 
    cout << "Fruits are equal\n"; 
    return true; 
    } 
    cout << "Fruits are different\n"; 
    return false; 
} 

int main(void) 
{ 
    // Fun with fruit. 
    Fruit * p_fruit_1 = new Strawberry; 
    Fruit * p_fruit_2 = new Banana; 
    Fruit * p_fruit_3 = new Strawberry; 

    // Is this valid, comparing two different fruits, when 
    // we just want to compare two strawberries? 
    if (Compare_Fruits(p_fruit_1, p_fruit_3)) // OK, both are strawberries 
    { 
    // ... 
    } 
    if (Compare_Fruits(p_fruit_1, p_fruit_2)) // Not OK, two different fruits. 
    { 
    // ... 
    } 
    return 0; 
} 

Дело в том, что если вы реализуете равную работу в базовом классе, так что потомки могут сравнить экземпляры, вы сделали плохое решение. Имейте в виду, что я могу передать указатель на экземпляр одного потомка (Strawberry) методу сравнения другого потомка (Banana), потому что функция равенства основана на указателях на базовый класс. К сожалению, нет способа рассказать, сколько или всех потомков, полученных из базового класса.

Для обеспечения безопасности программирования я настоятельно рекомендую не размещать виртуальные операторы сравнения в базовом классе. Базовый класс должен иметь операторы сравнения, объявленные защищенными, что сравнить только базовые элементы данных. Этот метод будет вызываться потомками.

+0

Как тогда , если у вас есть пара объектов, известных только указателем базового класса или ссылкой, знаете ли вы, равны ли они? –

+0

Если два объекта, известные указателем базового класса или ссылкой, можно сравнить только с данными базового класса. Вы можете сравнивать только контентное равенство тогда и только тогда, когда два объекта являются экземплярами одного и того же класса. Опять же, что сравнивается, когда базовый класс является «Life_Form», а один экземпляр - деревом, а другой - пауком? Это не имеет смысла. В моем проекте, где «Поле» является базовым классом, у меня есть «Запись», которая представляет собой контейнер «Поле». Как я могу быть уверен, что я не сравниваю «Поле :: Текст» с полем «Окно: Двойной»? –

+0

Используя 'dynamic_cast' с функцией виртуального сравнения, как показано в вопросе, вы можете легко поместить функцию сравнения в базовый класс - вы просто не можете ее реализовать. –