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

// Queueint не конкретизируется при таком использовании в foo()

void foo( Queueint &qi )

{

Queueint *pqi =

// ...

}

Определение класса необходимо знать, когда определяется объект этого типа. В следующем примере определение obj1 ошибочно: чтобы выделить для него память, компилятору необходимо знать размер класса Matrix:

class Matrix;

Matrix obj1; // ошибка: класс Matrix не определен

class Matrix { ... };

Matrix obj2; // правильно

Таким образом, конкретизация происходит тогда, когда определяется объект класса, конкретизированного по этому шаблону. В следующем примере определение объекта qi приводит к конкретизации шаблона Queue:

Queueint qi; // конкретизируется Queueint

Определение Queueint становится известно компилятору именно в этой точке, которая называется точкой конкретизации данного класса.

Если имеется указатель или ссылка на конкретизированный шаблон, то конкретизация также производится в момент обращения к объекту, на который они ссылаются. В определенной выше функции foo() класс Queue конкретизируется в следующих случаях: когда разыменовывается указатель pqi, когда ссылка qi используется для получения значения именуемого объекта и когда pqi или qi употребляются для доступа к членам или функциям-членам этого класса:

void foo( Queueint &qi )

{

Queueint *pqi =

// Queue конкретизируется в результате вызова функции-члена

pqi-add( 255 );

// ...

}

Определение Queueint становится известным компилятору еще до вызова функции-члена add() из foo().

Напомним, что в определении шаблона класса Queue есть также ссылка на шаблон QueueItem:

template class Type

class Queue {

public:

// ...

private:

QueueItemType *front;

QueueItemType *back;

};

При конкретизации Queue типом int члены front и back становятся указателями на QueueItem. Следовательно, конкретизированный экземпляр Queueint ссылается на экземпляр QueueItem, конкретизированный типом int. Но поскольку соответствующие члены являются указателями, то QueueItemint конкретизируется лишь в момент их разыменования в функциях-членах класса Queueint.

Наш класс QueueItem служит вспомогательным средством для реализации класса Queue и не будет непосредственно употребляться в вызывающей программе. Поэтому пользовательская программа способна манипулировать только объектами Queue. Конкретизация шаблона QueueItem происходит лишь в момент конкретизации шаблона класса Queue или его членов. (В следующих разделах мы рассмотрим конкретизации членов шаблона класса.)

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

template class Type

class кретизация производится для объемного типа (скажем, Matrix), то накладные расходы, вызванные неправильным выбором на этапе проектирования, становятся неприемлемыми. (В разделе 7.3 обсуждались вопросы производительности, связанные с передачей параметров по значению и по ссылке.) Поэтому аргумент конструктора объявляется как ссылка на константный тип:

QueueItem( const Type & );

Следующее определение приемлемо, если у типа, для которого конкретизируется QueueItem, нет ассоциированного конструктора:

template class Type

class QueueItem {

// ...

public:

// потенциально неэффективно

QueueItem( const Type &t ) {

item = t; next = 0;

}

};

Если аргументом шаблона является тип класса с конструктором (например, string), то item инициализируется дважды! Конструктор по умолчанию string вызывается для инициализации item перед выполнением тела конструктора QueueItem. Затем для созданного объекта item производится почленное присваивание. Избежать такого можно с помощью явной инициализации item в списке инициализации членов внутри определения конструктора QueueItem:

template class Type

class QueueItem {

// ...

public:

// item инициализируется в списке инициализации членов конструктора

QueueItem( const Type &t )

: item(t) { next = 0; }

};

(Списки инициализации членов и основания для их применения обсуждались в разделе 14.5.)

16.2.1. Аргументы шаблона для параметров-констант