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

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


class Base { public:

foo( int );

...

protected: int bar; double foo bar;

class Derived : public Base {

public:

foo( string ); bool bar( Base *pb ); void foobar(); ... protected:

string bar;

Derived d; d.foo( 1024 );

Исправьте ошибки в каждом из следующих фрагментов кода:

(c) bool Derived::bar( Base *pb )

(b) void Derived::foobar() { bar = 1024; } { return foo bar == pb-> foo bar; }

17.4. Конструирование базового и производного классов

Напомним, что объект производного класса состоит из одного или более подобъектов, соответствующих базовым классам, и части, относящейся к самому производному. Например, NameQuery состоит из подобъекта Query и объекта-члена string. Для иллюстрации поведения конструктора производного класса введем еще один член

class NameQuery : public Query {

public: ...

protected:

bool present; string name;

встроенного типа:

Если present установлен в false, то слово name в тексте отсутствует.



inline NameQuery::

NameQuery( const string &name )

: name( name ), present( false )

являющимся объектами классов; подробности см. в разделе 14.5):

Для передачи одного или более аргументов конструктору базового класса также разрешается использовать список инициализации членов. В следующем примере мы передаем конструктору string аргумент name, а конструктору базового класса Query -

inline NameQuery::

NameQuery( const string &name,

vector<location> *ploc ) : name( name ), Query( *ploc ), present( true )

объект, адресованный указателем ploc:

Хотя Query помещен в список инициализации вторым, его конструктор всегда вызывается раньше конструктора для name. Порядок их вызова следующий:

Конструктор базового класса. Если базовых классов несколько, то конструкторы вызываются в порядке их следования в списке базовых классов, а не в порядке появления в списке инициализации. (О множественном наследовании в этой связи мы поговорим в главе 18.)

Конструктор объекта-члена. Если в классе есть несколько таких членов, то конструкторы вызываются в порядке их объявления в классе, а не в порядке появления в списке инициализации (подробнее см. раздел 14.5).

Рассмотрим случай, когда в NameQuery конструктор не определен. Тогда при определении объекта этого класса

NameQuery nq;

по очереди вызывается конструктор по умолчанию Query, а затем конструктор по умолчанию класса string (ассоциированный с объектом name). Член present остается неинициализированным, что потенциально может служить источником ошибок. Чтобы инициализировать его, можно так определить конструктор по умолчанию для класса NameQuery:

inline NameQuery::NameQuery() { present = false; }

Теперь при определении nq вызываются три конструктора по умолчанию: для базового класса Query, для класса string при инициализации члена name и для класса NameQuery.

А как передать аргумент конструктору базового класса Query? Ответить на этот вопрос можно, рассуждая по аналогии.

Для передачи одного или более аргументов конструктору объекта-члена мы используем список инициализации членов (здесь можно также задать начальные значения членам, не



class Query {

public: ...

protected:

set<short> * solution; vector<location> loc;

...

В нашем базовом классе объявлено два нестатических члена: solution и loc: };

Конструктор Query по умолчанию должен явно инициализировать только член solution. Для инициализации loc автоматически вызывается конструктор класса vector. Вот реализация нашего конструктора:

inline Query::Query(): solution( 0 ) {} В Query нам понадобится еще один конструктор, принимающий ссылку на вектор

inline Query::

Query( const vector< locaton > &loc ) : solution( 0 ), loc( loc )

позиций:

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

Какой уровень доступа обеспечить для конструкторов? Мы не хотим объявлять их открытыми, так как предполагается, что Query будет существовать в программе только в

Конструктор производного класса.

Конструктор производного класса должен стремиться передать значение члена базового класса подходящему конструктору того же класса, а не присваивать его напрямую. В противном случае реализации двух классов становятся сильно связанньми и тогда изменить или расширить реализацию базового будет затруднительно. (Ответственность разработчика базового класса ограничивается предоставлением подходящего множества конструкторов.)

В оставшейся части этого раздела мы последовательно изучим конструктор базового класса и конструкторы четырех производных от него, а после этого рассмотрим альтернативный дизайн иерархии классов Query, чтобы познакомиться с иерархиями глубиной больше двух. В конце раздела речь пойдет о деструкторах классов.

17.4.1. Конструктор базового класса



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

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