|
Программирование >> Инициализация объектов класса, структура
template <class Type> void Queue<Type>::add( const Type &val ) { . .. } он сохраняет внутреннее представление Queue<Type>::add() . Позже, когда в программе встречается фактическое употребление этой функции-члена, допустим через объект типа Queue<int>, компилятор конкретизирует Queue<int>::add(const int &) , пользуясь #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 ); ... таким представлением: Конкретизация шаблона класса некоторым типом не приводит к автоматической конкретизации всех его членов тем же типом. Член конкретизируется только при использовании в таком контексте, где необходимо его определение (т.е. вложенный тип употреблен так, что требуется его полное определение; вызвана функция-член или взят ее адрес; имеется обращение к значению статического члена). Конкретизация функций-членов и статических членов шаблонов класса поднимает те же вопросы, которые м1 уже обсуждали для шаблонов функций в разделе 10.5. Чтобы компилятор мог конкретизировать функцию-член или статический член шаблона класса, должно ли определение члена быть видимым в момент конкретизации? Например, должно ли определение функции-члена add() появиться до ее конкретизации типом int в main() ? Следует ли помещать определения функций-членов и статических членов шаблонов класса в заголовочные файлы (как мы поступаем с определениями встроенных функций), которые включаются всюду, где применяются их конкретизированные экземпляры? Или конкретизации определения шаблона достаточно для того, чтобы этими членами можно было пользоваться, так что определения членов можно оставлять в файлах с исходными текстами (где обычно располагаются определения невстроенных функций-членов и статических членов)? Для ответа на эти вопросы нам придется вспомнить модель компиляции шаблонов в C++, где формулируются требования к организации программы, в которой определяются и употребляются шаблоны. Обе модели (с включением и с разделением), описанные в разделе 10.5, в полной мере применимы и к определениям функций-членов и статических данных-членов шаблонов классов. В оставшейся части этого раздела описываются обе модели и объясняется их использование с определениями членов. 16.8.1. Модель компиляции с включением В этой модели мы включаем определения функций-членов и статических членов шаблонов классов в каждый файл, где они конкретизируются. Для встроенных функций-членов, определенных в теле шаблона, это происходит автоматически. В противном ---- 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() { ... } Программа, в которой используется конкретизированная функция-член, должна перед конкретизацией включить заголовочный файл: случае такое определение следует поместить в один заголовочный файл с определением шаблона класса. Именно этой моделью mi и пользуемся в настоящей книге. Например, определения шаблонов Queue и QueueItemi, как и их функций-членов и статических членов, находятся в заголовочном файле Queue.h. Подобное размещение не лишено недостатков: определения функций-членов могут быть довольно большими и содержать детали реализации, которые неинтересны пользователям или должны быть скрыты от них. Кроме того, многократная компиляция одного определения шаблона при обработке разных файлов увеличивает общее время компиляции программы. Описанная модель (если она доступна) позволяет отделить интерфейс шаблона от реализации (т.е. от определений функций-членов и статических данных-членов). 16.8.2. Модель компиляции с разделением В этой модели определение шаблона класса и определения встроенных функций-членов помещаются в заголовочный файл, а определения невстроенных функций-членов и статических данн1х-членов - в файл с исходным текстом программы. Иными словами, определения шаблона класса и его членов организованы так же, как определения ----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 template <class Type> определении или объявлении нужно поставить ключевое слово export: 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() :
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |