Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Модель компиляции с разделением



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

// ---- Queue.h ----

// объявляет Queue как экспортируемый шаблон класса

export template < class Type>

class Queue {

//...

public:

Type& remove();

void add( const Type & );

//...

};

// ---- Queue.C ----

// экспортированное определение шаблона класса Queue

// находится в Queue.h

#include " Queue.h"

 

template < class Type>

void Queue< Type>:: add( const Type & val ) {... }

 

template < class Type>

Type& Queue< Type>:: remove() {... }

Программа, в которой используется конкретизированная функция-член, должна перед конкретизацией включить заголовочный файл:

// ---- User.C ----

#include " Queue.h"

 

int main() {

// конкретизация Queue< int>

Queue< int> *p_qi = new Queue< int>;

int ival;

//...

// правильно: конкретизация Queue< int>:: add( const int & )

p_qi-> add( ival );

//...

}

Хотя определение шаблона для функции-члена add() не видно в файле User.C, конкретизированный экземпляр Queue< int>:: add(const int & ) вызывать оттуда можно. Но для этого шаблон класса необходимо объявить экспортируемым.

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

Чтобы объявить шаблон класса экспортируемым, перед словом template в его определении или объявлении нужно поставить ключевое слово export:

export template < class Type>

class Queue {... };

В нашем примере слово export применено к шаблону класса Queue в файле Queue.h; этот файл включен в файл Queue.C, содержащий определения функций-членов add() и remove(), которые автоматически становятся экспортируемыми и не должны присутствовать в других файлах перед конкретизацией.

Отметим, что, хотя шаблон класса объявлен экспортируемым, его собственное определение должно присутствовать в файле User.C. Конкретизация Queue< int>:: add() в User.C вводит определение класса, в котором объявлены функции-члены Queue< int>:: add() и Queue< int>:: remove(). Эти объявления обязаны предшествовать вызову указанных функций. Таким образом, слово export влияет лишь на обработку функций-членов и статических данных-членов.

экспортируемыми можно объявлять также отдельные члены шаблона. В этом случае ключевое слово export указывается не перед шаблоном класса, а только перед экспортируемыми членами. Например, если автор шаблона класса Queue хочет экспортировать лишь функцию-член Queue< Type>:: add() (т.е. изъять из заголовочного файла Queue.h только ее определение), то слово export можно указать именно в определении функции-члена add():

// ---- Queue.h ----

template < class Type>

class Queue {

//...

public:

Type& remove();

void add( const Type & );

//...

};

 

// необходимо, так как remove() не экспортируется

template < class Type>

Type& Queue< Type>:: remove() {... }

// ---- Queue.C ----

#include " Queue.h"

 

// экспортируется только функция-член add()

export template < class Type>

void Queue< Type>:: add( const Type & val ) {... }

Обратите внимание, что определение шаблона для функции-члена remove() перенесено в заголовочный файл Queue.h. Это необходимо, поскольку remove() более не находится в экспортируемом шаблоне и, следовательно, ее определение должно быть видно во всех файлах, где вызываются конкретизированные экземпляры.

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

· при редактировании связей возникает ошибка, показывающая, что один и тот же член шаблона класса определен несколько раз;

· компилятор неоднократно конкретизирует некоторый член одним и тем же множеством аргументов шаблона, что приводит к ошибке повторного определения во время связывания программы;

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

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

Модель с разделением позволяет отделить интерфейс шаблона класса от его реализации и организовать программу так, что эти интерфейсы помещаются в заголовочные файлы, а реализации – в файлы с исходным текстом. Однако не все компиляторы поддерживают данную модель, а те, которые поддерживают, не всегда делают это правильно: для этого требуется более изощренная среда программирования, которая доступна не во всех реализациях C++.

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


Поделиться:



Последнее изменение этой страницы: 2019-04-09; Просмотров: 278; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.012 с.)
Главная | Случайная страница | Обратная связь