С++ для начинающих

         

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


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

// ---- 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() более не находится в экспортируемом шаблоне и, следовательно, ее определение должно быть видно во всех файлах, где вызываются конкретизированные экземпляры.

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

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



  • Содержание раздела