16.8.2. Модель компиляции с разделением
16.8.2. Модель компиляции с разделением
В этой модели определение шаблона класса и определения встроенных функций-членов помещаются в заголовочный файл, а определения невстроенных функций-членов и статических данных-членов - в файл с исходным текстом программы. Иными словами, определения шаблона класса и его членов организованы так же, как определения обычных классов (не шаблонов) и их членов:
// ---- 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 QueueType::add( const Type &val ) { ... }
template class Type
Type& Queue&Type&::remove() { ... }
Программа, в которой используется конкретизированная функция-член, должна перед конкретизацией включить заголовочный файл:
// ---- User.C ----
#include "Queue.h"
int main() {
// конкретизация Queue
Queue *p_qi = new Queue;
int ival;
// ...
// правильно: конкретизация Queue::add( const int & )
p_qi-add( ival );
// ...
}
Хотя определение шаблона для функции-члена add() не видно в файле User.C, конкретизированный экземпляр Queue::add(const int &) вызывать оттуда можно. Но для этого шаблон класса необходимо объявить экспортируемым.
Если он экспортируется, то для использования конкретизированных функций-членов или статических данных-членов необходимо знать лишь определение самого шаблона. Определения членов могут отсутствовать в тех файлах, где они конкретизируются.
Чтобы объявить шаблон класса экспортируемым, перед словом template в его определении или объявлении нужно поставить ключевое слово export:
export template class Type
class Queue { ... };
В нашем примере слово export применено к шаблону класса Queue в файле Queue.h; этот файл включен в файл Queue.C, содержащий определения функций-членов add() и remove(), которые автоматически становятся экспортируемыми и не должны присутствовать в других файлах перед конкретизацией.
Отметим, что, хотя шаблон класса объявлен экспортируемым, его собственное определение должно присутствовать в файле User.C. Конкретизация Queue::add() в User.C вводит определение класса, в котором объявлены функции-члены Queue::add() и Queue::remove(). Эти объявления обязаны предшествовать вызову указанных функций. Таким образом, слово export влияет лишь на обработку функций-членов и статических данных-членов.
экспортируемыми можно объявлять также отдельные члены шаблона. В этом случае ключевое слово export указывается не перед шаблоном класса, а только перед экспортируемыми членами. Например, если автор шаблона класса Queue хочет экспортировать лишь функцию-член Queue::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 QueueType::add( const Type &val ) { ... }
Обратите внимание, что определение шаблона для функции-члена remove() перенесено в заголовочный файл Queue.h. Это необходимо, поскольку remove() более не находится в экспортируемом шаблоне и, следовательно, ее определение должно быть видно во всех файлах, где вызываются конкретизированные экземпляры.
* Определение функции-члена или статического члена шаблона объявляется экспортируемым только один раз во всей программе. Поскольку компилятор обрабатывает файлы последовательно, он обычно не в состоянии определить, что эти члены объявлены экспортируемыми в нескольких исходных файлах. В таком случае результаты могут быть следующими: при редактировании связей возникает ошибка, показывающая, что один и тот же член шаблона класса определен несколько раз;
* компилятор неоднократно конкретизирует некоторый член одним и тем же множеством аргументов шаблона, что приводит к ошибке повторного определения во время связывания программы;
* компилятор конкретизирует член с помощью одного из экспортированных определений шаблона, игнорируя все остальные.
Следовательно, нельзя утверждать, что при наличии в программе нескольких определений экспортированного члена шаблона обязательно будет сгенерирована ошибка. Создавая программу, надо быть внимательным и следить за тем, чтобы определения членов находились только в одном исходном файле.
Модель с разделением позволяет отделить интерфейс шаблона класса от его реализации и организовать программу так, что эти интерфейсы помещаются в заголовочные файлы, а реализации - в файлы с исходным текстом. Однако не все компиляторы поддерживают данную модель, а те, которые поддерживают, не всегда делают это правильно: для этого требуется более изощренная среда программирования, которая доступна не во всех реализациях C++.
В нашей книге используется только модель с включением, так как примеры работы с шаблонами небольшие и хотелось, чтобы они компилировались максимально большим числом компиляторов.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
3.8.1. Подготовка к компиляции
3.8.1. Подготовка к компиляции Прежде чем выполнять какие-то действия по обновлению ядра, нужно подготовиться к самому худшему, а именно — к краху системы. Да, неправильные действия в самом деле могут нарушить работу или сделать невозможной загрузку системы. Ядро — это
Проблемы, возникающие при компиляции ядра
Проблемы, возникающие при компиляции ядра Если вы корректно установили опции, компиляция ядра, как правило, проходит без проблем, но в некоторых случаях возникают ошибки. Проблемы, встречающиеся при компиляции ядра, описаны ниже.• Ошибки в исходном коде или
17.4. О компиляции нового ядра
17.4. О компиляции нового ядра 17.4.1 Зачем вообще нужно компилировать ядро? Как было сказано в начале данного раздела, основная функция ядра состоит в том, чтобы обеспечить взаимодействие с аппаратурой компьютера. Обслуживание некоторых составляющих аппаратного
17.4.2 Что надо знать до начала компиляции
17.4.2 Что надо знать до начала компиляции Пожалуй, самое первое, к чему нужно быть готовым, приступая к компиляции ядра, - это то, что процедура эта длительная. Так что не рассчитывайте скомпилировать ядро "между делом", в свободную минутку. Заранее планируйте, что потратите
Распространенные проблемы компиляции Asterisk
Распространенные проблемы компиляции Asterisk Существует множество проблем компиляции, с которыми часто сталкиваются пользователи. Далее рассматриваются некоторые самые распространенные из них и способы их решения.Сначала давайте рассмотрим некоторые ошибки, которые
Ошибки depmod во время компиляции
Ошибки depmod во время компиляции Если во время компиляции возникают ошибки depmod, вероятнее всего, отсутствует символическая ссылка на исходные файлы ядра Linux. Если исходные файлы используемого ядра Linux не установлены, необходимо скачать их в Интернете c сайта http://kernel.org,
Часть первая: "Что нужно для компиляции простейшего драйвера?"
Часть первая: "Что нужно для компиляции простейшего драйвера?" Для разных типов Windows вам понадобиться разный набор программ.В любом случае надо скачать Win DDK (Driver Development Kit), для той платформы, под которую пишется драйвер. Его можно брать с разных источников, лично я
Правило 31: Уменьшайте зависимости файлов при компиляции
Правило 31: Уменьшайте зависимости файлов при компиляции Рассмотрим самую обыкновенную ситуацию. Вы открываете свою программу на C++ и вносите незначительные изменения в реализацию класса. Заметьте, не в интерфейс класса, а просто в реализацию – только в закрытые члены.
Цикл компиляции страницы ASP.NET 2.0
Цикл компиляции страницы ASP.NET 2.0 Независимо от того, какую модель страницы вы использовали (одномодульную страницу или страницу с внешним кодом поддержки), ваши файлы *.aspx (как и любые связанные файлы с кодом поддержки) динамически компилируются в действительный
Цикл компиляции одномодульных страниц
Цикл компиляции одномодульных страниц При использовании модели одномодульной страницы, HTML-разметка, блоки ‹script› и определения Web-элементов управления динамически компилируются в тип класса, производный от System.Web.UI.Page.Имя этого класса получается из имени файла *.aspx с
Цикл компиляции многомодульных страниц
Цикл компиляции многомодульных страниц Процесс компиляции страницы, построенной по модели с внешним кодом поддержки, подобен процессу компиляции одномодульной страницы. Однако получающийся при этом тип, производный от System.Web.UI.Page, компонуется из трех файлов (да, именно
10.5. Модели компиляции шаблонов А
10.5. Модели компиляции шаблонов А Шаблон функции задает алгоритм для построения определений множества экземпляров функций. Сам шаблон не определяет никакой функции. Например, когда компилятор видит шаблон:template typename TypeType min( Type t1, Type t2 ){return t1 t2 ? t1 : t2;}он сохраняет
10.5.1. Модель компиляции с включением
10.5.1. Модель компиляции с включением Согласно этой модели мы включаем определение шаблона в каждый файл, где этот шаблон конкретизируется. Обычно оно помещается в заголовочный файл, как и для встроенных функций. Именно такой моделью мы пользуемся в нашей книге.
10.5.2. Модель компиляции с разделением
10.5.2. Модель компиляции с разделением Согласно этой модели объявления шаблонов функций помещаются в заголовочный файл, а определения – в файл с исходным текстом программы, т.е. объявления и определения шаблонов организованы так же, как в случае с невстроенными (non-inline)
16.8. Шаблоны классов и модель компиляции A
16.8. Шаблоны классов и модель компиляции A Определение шаблона класса - это лишь предписание для построения бесконечного множества типов классов. Сам по себе шаблон не определяет никакого класса. Например, когда компилятор видит:template class Typeclass Queue { ... };он только сохраняет
16.8.1. Модель компиляции с включением
16.8.1. Модель компиляции с включением В этой модели мы включаем определения функций-членов и статических членов шаблонов классов в каждый файл, где они конкретизируются. Для встроенных функций-членов, определенных в теле шаблона, это происходит автоматически. В противном