Программирование >>  Инициализация объектов класса, структура 

1 ... 286 287 288 [ 289 ] 290 291 292 ... 395


bool

NameQuery::

compare ( const Query *pery ) {

правильно: защенн член подобъекта Query int matches = loc.size();

правильно: используется открытый метод доступа int itsMatches = pquery->locations()->size();

return matches == itsMatches;

location() :

Однако проблема заключается в неправильном проектировании. Поскольку loc - это член базового класса Query, то место compare() среди членов базового, а не производного класса. Во многих случаях подобные проблемы могут быть решены путем переноса некоторой операции в тот класс, где находится недоступный член, как в приведенном примере.

Этот вид ограничения доступа не распространяется на доступ изнутри класса к другим

bool

NameQuery::

compare( const NameQuery *pname ) {

int myMatches = loc.size(); правильно int itsMatches = name-> loc.size(); тоже правильно

return matches == itsMatches;

объектам того же класса:

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

Рассмотрим инициализацию указателя на базовый Query адресом объекта производного NameQuery:

Query *pb = new NameQuery( sprite ); При вызове виртуальной функции, определенной в базовом классе Query, например:

pb->eval(); вызывается NameQuery::eval()

У объекта NameQuery есть доступ к защищенным членам только одного объекта Query -подобъекта самого себя. Прямое обращение к ним из производного класса осуществляется через неявный указатель this (см. раздел 13.4). Первая реакция на ошибку компиляции -переписать функцию compare() с использованием открытой функции-члена



ошибка: suffix() - не член класса Query

компиляции:

pb->suffix();

Обращение к члену или невиртуальной функции-члену класса NameQuery через

ошибка: name - не член класса Query

pb тоже вызывает ошибку компиляции:

pb-> name;

ошибка: у класса Query нет базового класса NameQuery

Квалификация имени члена в этом случае не помогает:

pb->NameQuery:: name;

В C++ с помощью указателя на базовый класс можно работать только с данными и функциями-членами, включая виртуальные, которые объявлены (или унаследованы) в самом этом классе, независимо от того, какой фактический объект адресуется указателем. Объявление функции-члена виртуальной откладывает решение вопроса о том, какой экземпляр функции вызвать, до выяснения (во время выполнения программы) фактического типа объекта, адресуемого pb.

Такой подход может показаться недостаточно гибким, но у него есть два весом1х преимущества:

поиск виртуальной функции-члена во время выполнения никогда не закончится неудачно из-за того, что фактический тип класса не существует. В таком случае программа просто не смогла бы откомнилироваться;

механизм виртуализации можно оптимизировать. Часто вызов такой функции оказывается не дороже, чем косвенный вызов функции по указателю (детально этот вопрос рассмотрен в [LIPPMAN96a]).

В базовом классе Query определен статический член text file:

static vector<string> * text file;

вызывается функция из NameQuery. За исключением вызова виртуальной функции, объявленной в Query и переопределенной в NameQuery, другого способа напрямую добраться до членов класса NameQuery через указатель pb не существует:

(a) если в Query и NameQuery объявлена: некоторые невиртуальные функции-члены с одинаковым именем, то через pb всегда вызывается экземпляр из Query;

(b) если в Query и NameQuery объявлены одноименн1е члены, то через pb обращение происходит к члену класса Query;

(c) если в NameQuery имеется виртуальная функция, отсутствующая в Query, скажем suffix() , то попытка вызвать ее через pb приводит к ошибке



class Query {

friend class NameQuery;

public: ...

базового класса напрямую, то он должен быть объявлен другом базового: };

Теперь объект NameQuery может обращаться не только к закрыт1м членам своего подобъекта, соответствующего базовому классу, но и к закрытым и защищенным членам любых объектов Query.

А если м1 произведем от NameQuery класс StringQuery? Он будет поддерживать сокращенную форму запроса AndQuery, и вместо

beautiful && fiery && bird

можно будет написать:

i beautiful fiery bird

Унаследует ли StringQuery от класса NameQuery дружественные отношения с Query? Нет. Отношение дружественности не наследуется. Производный класс не становится другом класса, который объявил своим другом один из базовых. Если производному классу требуется стать другом одного или более классов, то эти классы должны предоставить ему соответствующие права явно. Например, у класса StringQuery нет никаких специальных прав доступа по отношению к Query. Если расширенный доступ необходим, то Query должен разрешить его явно.

Упражнение 17.6

Даны следующие определения базового и производных классов:

Создается ли при порождении класса NameQuery второй экземпляр text file, уникальный именно для него? Нет. Все объекты производного класса ссылаются на тот же самый, единственный разделяемый статический член. Сколько бы ни было производных классов, существует лишь один экземпляр text file. Можно обратиться к нему через объект производного класса с помощью синтаксиса доступа:

nameQueryObject. text file; правильно Наконец, если производный класс хочет получить доступ к закрытым членам своего



1 ... 286 287 288 [ 289 ] 290 291 292 ... 395

© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика