Query&
Query::
operator=( const Query &rhs )
{
// предотвратить присваивание самому себе
if ( &rhs != this )
{
_paren = rhs._paren;
_loc = rhs._loc;
delete _solution;
_solution = 0;
}
return *this;
};
В классе NameQuery явный копирующий оператор присваивания не нужен. Присваивание одного объекта NameQuery другому выполняется в два шага:
Для присваивания подобъектов Query двух объектов NameQuery вызывается явный копирующий оператор присваивания класса Query.
Для присваивания членов string вызывается явный копирующий оператор присваивания этого класса.
Для объектов NameQuery вполне достаточно почленного присваивания по умолчанию.
В каждом из классов NotQuery, AndQuery и OrQuery для безопасного копирования операндов требуется явный копирующий оператор присваивания. Вот его реализация для NotQuery:
inline NotQuery&
NotQuery::
operator=( const NotQuery &rhs )
{
// предотвратить присваивание самому себе
if ( &rhs != this )
{
// вызвать копирующий оператор присваивания Query
this-Query::operator=( rhs );
// скопировать операнд
_op = rhs._op-clone();
}
return *this;
}
В отличие от копирующего конструктора, в копирующем операторе присваивания нет специальной части, через которую вызывается аналогичный оператор базового класса. Для этого используются две синтаксических конструкции: явный вызов, продемонстрированный выше, и явное приведение типа, как в следующем примере:
(*static_castQuery*(this)) = rhs;
(Реализация копирующих операторов присваивания в классах AndQuery и OrQuery выглядит так же, поэтому мы оставим ее в качестве упражнения.)
Ниже предложена небольшая программа для тестирования данной реализации. Мы создаем или копируем объект, а затем распечатываем его.
#include "
Query.h"
int
main()
{
NameQuery nm( "alice" );
NameQuery nm( "emma" );
NotQuery nq1( &nm );
cout "notQuery 1: " nq1 endl;
NotQuery nq2( nq1 );
cout "notQuery 2: " nq2 endl;
NotQuery nq3( &nm2 );
cout "notQuery 3: " nq3 endl;
nq3 = nq2;
cout "notQuery 3 присвоено значение nq2: " nq3 endl;
AndQuery aq( &nq1, &nm2 );
cout "AndQuery : " aq endl;
AndQuery aq2( aq );
cout "AndQuery 2: " aq2 endl;
AndQuery aq3( &nm, &nm2 );
cout "AndQuery 3: " aq3 endl;
aq2 = aq3;
cout "AndQuery 2 после присваивания: " aq2 endl;
}
После компиляции и запуска программа печатает следующее:
notQuery 1: ! alice
notQuery 2: ! alice
notQuery 3: ! emma
notQuery 3 присвоено значение nq2: ! alice
AndQuery : ! alice && emma
AndQuery 2: ! alice && emma
AndQuery 3: alice && emma
AndQuery 2 после присваивания: alice && emma
Упражнение 17.18
Реализуйте копирующие конструкторы в классах AndQuery и OrQuery.
Упражнение 17.19
Реализуйте копирующие операторы присваивания в классах AndQuery и OrQuery.
Упражнение 17.20
Что указывает на необходимость реализации явных копирующего конструктора и копирующего оператора присваивания?
17.7. Управляющий класс UserQuery
Если имеется запрос такого типа:
fiery && ( bird || potato )
то в нашу задачу входит построение эквивалентной иерархии классов:
AndQuery
NameQuery( "fiery" )
OrQuery
NameQuery( "bird" )
NameQuery( "potato" )
Как лучше всего это сделать? Процедура вычисления ответа на запрос напоминает функционирование конечного автомата. Мы начинаем с пустого состояния и при обработке каждого элемента запроса переходим в новое состояние, пока весь запрос не будет разобран. В основе нашей реализации лежит одна инструкция switch внутри операции, которую мы назвали eval_query(). Слова запроса считываются одно за другим из вектора строк и сравниваются с каждым из возможных значений:
vectorstring::iterator
it = _query-begin(),
end_it = _query-end();
for ( ; it != end_it; ++it )
switch( evalQueryString( *it ))
{
case WORD:
evalWord( *it );
break;
case AND:
evalAnd();
break;
case OR: