Оператор равенства должен возвращать значение false при попытке сравнить объекты разных типов. Например, если попытаться сравнивать объект базового класса с объектом производного, оператор == должен возвратить значение false.

С учетом этого наблюдения можно прийти к выводу, что решить данную проблему можно с использованием RTTI. Определим оператор равенства, параметр которого будет ссылкой на тип базового класса. Оператор равенства будет использовать оператор typeid для проверки наличия у операндов одинакового типа. Если тип операндов разный, оператор возвратит значение false. В противном случае он возвратит виртуальную функцию equal(). Каждый класс определит функцию equal() так, чтобы сравнить переменные-члены собственного типа. Эти операторы получают параметр типа Base&, но приводят операнд к собственному типу, прежде чем начать сравнение.

Иерархия класса

Чтобы сделать концепцию более конкретной, предположим, что рассматриваемые классы выглядят следующим образом:

class Base {

 friend bool operator==(const Base&, const Base&);

public:

 // члены интерфейса для класса Base

protected:

 virtual bool equal(const Base&) const;

 // данные и другие члены реализации класса Base

};

class Derived: public Base {

public:

 // данные и другие члены реализации класса Base

protected:

 bool equal(const Base&) const;

 // данные и другие члены реализации класса Derived

};

Оператор равенства, чувствительный к типу

Рассмотрим, как можно было бы определить общий оператор равенства:

bool operator==(const Base &lhs, const Base &rhs) {

 // возвращает false, если типы не совпадают; в противном случае вызов

 // виртуальной функции equal()

 return typeid(lhs) == typeid(rhs) && lhs.equal(rhs);

}

Этот оператор возвращает значение false, если операнды имеют разный тип. Если они имеют одинаковый тип, оператор делегирует реальную работу по сравнению операндов виртуальной функции equal(). Если операнды являются объектами класса Base, вызывается функция Base::equal(), а если объектами класса Derived — то функция Derived::equal().

Виртуальная функция equal()

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

bool Derived::equal(const Base &rhs) const {

 // известно, что типы равны, значит, приведение не передаст

 // исключения

 auto r = dynamic_cast(rhs);

 // действия по сравнению двух объектов класса Derived и возвращению

 // результата

}

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

Функция equal() базового класса

Эта функция гораздо проще других:

bool Base::equal(const Base &rhs) const {

 // действия по сравнению двух объектов класса Base

}

Здесь нет никакой необходимости в приведении аргументов перед применением. Оба они, и *this и параметр, являются объектами класса Base, поэтому все доступные для него функции содержатся в классе объекта.

<p>19.2.4. Класс <code>type_info</code></p>

Точное определение класса type_info зависит от компилятора, но стандарт гарантирует, что класс будет определен в заголовке typeinfo и предоставлять, по крайней мере, те функции, которые перечислены в табл. 19.1.

Этот класс обладает также открытым виртуальным деструктором, поскольку он предназначен для использования в качестве базового класса. Если компилятор позволяет предоставить дополнительную информацию о типе, для этого следует воспользоваться классом, производным от класса type_info.

Таблица 19.1. Функции класса type_info

Перейти на страницу:

Похожие книги