|
Программирование >> Инициализация объектов класса, структура
void print ( Query object, const Query *pointer, const Query &reference до момента выполнения невозможно определить, какой экземпляр print() вызывается r->print(); pointer->print(); reference.print(); всегда вызается Query::print() object.print(); int main() { NameQuery firebird( firebird ); print( firebird, &firebird, firebird ); ссылки, но не сами объекты: В данном примере оба обращения через указатель pointer и ссылку reference разрешаются своим динамическим типом; в обоих случаях вызывается NameQuery::print() . Обращение же через объект object всегда приводит к вызову Query::print(). (Пример программ:, в которой используется эффект усечения , приведен в разделе 18.6.2.) В следующих подразделах мы продемонстрируем определение и использование виртуальных функций в разных обстоятельствах. Каждая такая функция-член будет иллюстрировать один из аспектов объектно-ориентированного проектирования. 17.5.1. Виртуальный ввод/вывод Первая виртуальная операция, которую мы хотели реализовать, - это печать запроса на стандартный вывод либо в файл: ostream& print( ostream &os = cout ) const; Функцию print() следует объявить виртуальной, поскольку ее реализации зависят от типа, но нам нужно вызывать ее через указатель типа Query*. Например, для класса ostream& A\ndQuery::print ( ostream &os ) const { lop->print( os ); os << && ; rop->print( os ); AndQuery эта функция могла бы выглядеть так: является объектом NameQuery. Часть nq, принадлежащая NameQuery, усечена перед инициализацией qobject, поскольку она не помещается в область памяти, отведенную под объект Query. Для поддержки этой парадигма: приходится использовать указатели и class Query public: virtual ostreams print( ostream &os=cout ) const {} ... ее как пустую функцию, а потом сделаем чисто виртуальной: В базовом классе, где виртуальная функция появляется в первый раз, ее объявлению должно предшествовать ключевое слово virtual. Если же ее определение находится вне этого класса, повторно употреблять virtual не следует. Так, данное определение ошибка: кочевое слово virtual может только в определении класса появляться print() приведет к ошибке компиляции: virtual ostreams Query::print( ostreams ) const { ... } Правильный вариант не должен включать слово virtual. Класс, в котором впервые появляется виртуальная функция, должен определить ее или объявить чисто виртуальной (напомним, что пока мы определили ее как пустую). В производном классе может быть либо определена собственная реализация той же функции, которая в таком случае становится активной для всех объектов этого класса, либо унаследована реализация из базового класса. Если в производном классе определена собственная реализация, то говорят, что она замещает реализацию из базового. Прежде чем приступать к рассмотрению реализаций print() для наших четырех производных классов, обратим внимание на употребление скобок в запросе. Например, с помощью fiery ss bird shyly пользователь ищет вхождения пары слов Pfiery bird или одного слова shyly С другой стороны, запрос Необходимо объявить print() виртуальной функцией в абстрактном базовом Query, иначе мы не сможем вызвать ее для членов классов AndQury, OrQuery и NotQuery, являющихся указателями на операнды соответствующих запросов типа Query*. Однако для самого Query разумной реализации print() не существует. Поэтому мы определим fiery hair Если наши реализации print() не будут показывать скобки в исходном запросе, то для пользователя они окажутся почти бесполезными. Чтобы сохранить эту информацию, введем в наш абстрактный базовый класс Query два нестатических члена, а также функции доступа к ним (подобное расширение класса - естественная часть эволюции class Query { public: установить lparen и rparen void lparen( short lp ) { lparen = lp; } void rparen( short rp ) { rparen = rp; } получить значения lparen и short lparen() { return lparen; } short rparen() { return rparen; } напечатать левую и прав скобки void print lparen( short cnt, ostream& os ) const; void print rparen( short cnt, ostream& os ) const; protected: счетчики лев и прав скобок short lparen; short rparen; ... иерархии): }; lparen - это количество левых, а rparen - правых скобок, которое должно быть выведено при распечатке объекта. (В разделе 17.7 мы покажем, как вычисляются такие величины и как происходит присваивание обоим членам.) Вот пример обработки запроса с большим числом скобок: ==> ( untamed ( fiery ( shyly ) ) ) evaluate word: untamed lparen: 1 rparen: 0 evaluate Or lparen: 0 rparen: 0 [ fiery && ( bird hair ) найдет все вхождения любой из пар Pfiery bird
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |