Выбрать главу

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: