Программирование >>  Структура ядра и системные вызовы 

1 ... 6 7 8 [ 9 ] 10 11 12 ... 98


int mainO (flftr.

char* ptr = min ( С++- , UNIX ); double X = min(2.0, 3.0);

min (char*,- char*) min(T,T)

2.11.2. Шаблоны классов

Объявление шаблона класса имеет такой формальный синтаксис: template <список формальных параметров> class <имя класса> {

<объяБление>

За ключевым словом template в объявлении шаблона класса следует список формальных параметров, затем имя класса и его тело. Список формальных параметров заключается в символы < и >, и параметры в нем отделяются друг от друга запятыми. Вот пример объявления шаблона класса: template <class Т, int len> class foo (

. , T list[len]; };

Как и в объявлении шаблона функции, каждый параметр, объявленный в списке формальных параметров, должен быть использован в объявлении соответствующего шаблона класса хотя бы один раз. Более того, при каадой ссылке на имя шаблона класса должен указываться и список параметров, заключенный в угловые скобки (кроме случая, когда это делается внутри объявления класса). Объявим шаблон класса Array, который содержит массив типа Тс количеством элементов len. Параметры Г и len должны указываться при создании экземпляров этого шаблона. Обратите внимание на то, что в определении функции-конструктора указаны имя класса и список параметров:

template <class Tv int len>, class Array {

public:

Array 0; -Array 0 protected:

T list[len];

template <class TT, int len> inline Array<TT,len>::Array0

Системное программирование на C+-f для UNIX

Чтобы создать объект для специализированного экземпляра шаблона класса, пользователи указывают имя класса и фактические данные для списка параметров, заключенного в символы < и >. Так, чтобы создать объект класса Array, который содержит целочисленный массив из 100 элементов, нужно дать следующее его определение:

Array<int, 100> foo; foo - это объект

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

Объявим шаблон подкласса Array super, порожденный от шаблонов классов 67 и 62 Переменная foo определяется как экземпляр класса Array super, а ptr - это указатель на экземпляр класса Ы. Поскольку экземпляры шаблонов bl<int> и Array super<int> имеют параметры одного типа, то они совместимы и, следовательно, указателю ptr можно присвоить адрес foo. Однако экземпляры шаблонов bl<double> и Array super<int> весовместкмы, поэтому присваивание адреса foo указателю ptr2 будет ошибкой.,

template <class Туре>

class Array super: public bl<Type>, public :Ь2<Туре> {.. Array super<int> foo; . .

bl<int> *ptr = &foo; , .

bl<double> *ptr2 = &foo;

. .);

/ правильно 7/ ошибка

Внутри шаблонов классов могут объявляться дружественные функции и классы. Каждая из функций может быть:

* функцией или классом, объявленными без шаблона;

шаблоном;

специализированным экземпляром шаблона функции.

Сказанное относится и к дружественному классу, объявляемому внутри шаблона.

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

template <class U> class Container (

общий шаблон дружественного класса template <class Т> friend class general class;

общий шаблон дружественной функции

template <class UT> friend general func ( <UT>&, int );...

Глава 2. Обзор языка С++



дружественным является только экземпляр этого же типа U класса Array friend class Array<U>;

дружественным является только экземпляр этого же типа U функции friend ostreamS operator<< (osterams, Container<U>s);

нешаблонный дружественный класс friend class dates;

, нешаблонная дружественная функция frien void foo {);

В этом примере шаблон класса Container имеет формальный параметр типа и. Класс Container имеет несколько дружественных функций и классов; из них классы dates и foo являются дружественными для всех специализированных экземпляров класса Container. Шаблон класса Array и перегруженная операция << являются дружественными для специализированных экземпляров класса Container, если они используют параметры одного типа. Такик* образом, /4/га></ /> - дружественный класс для Container<int>, но Array<dou-b/e> таковым не является. Наконец, все специализированные экземпляры шаблона класса general class и шаблона функции general June - дружественные для всех специализированных экземпляров класса Container

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

template <class Т> class Array

1; 1;

public:

Array(int sz) { ar=new T[size=sz]; -Array{) { delete [sz] ar;); T& operator[](int) { return ar{i]; .protected: T* ar; int size;

специализированный конструктор типа double Array<double>::Array{ int size ){...}

определение специализированного класса Array class Array<char*>

- . !,i У i

public:

Array(int sz) { ar=new char[size=sz]; ),; -Array{) { delete [] ar; );

chars operator [ J (int i) { return ar(il; ) protected: char* ar; int size;

В шаблоне класса могут объявляться статические данные-члены. В каждом специализированном экземпляре такого шаблона имеется собственный набор статических данных-членов. Ниже объявляется шаблон класса Array с двумя статическими данными-членами: Array<T>::pool и Array<T>::pool sz. Эти статические переменные по умолчанию инициализируются соответственно в О и 100 для всех специализированных экземпляров класса Array:

template <class Т> class Array i

public:

Array (int sz) { ar = new char [sizep=3z]; }}

-Array0 (delete [sz] ar; );

void *operator new(size t);

void operator delete (void*, si2e t) < protected: Qj :n,]

char* ar;

int size;

static Array* pool;

static const int pool sz; );

template <class T> Array<T>* Array<T>;:pool = 0; template <class T> const int Array<T>::pool sz = 100;

Можно определить специализированный экземпляр статических данных-членов класса и задать для них уникальные начальные значения. Так, переменные Array<char>::poot и Array<char>::pool sz для экземпляра char класса Array определяются следующим образом:

Array<char>* Array<char>::роо1 = new char[1000]; Array<char>* Array<char>::pool sz = 1000;

Следует также сказать, что доступ к статическим данным-членам шаблона класса может осуществляться только через специализированный экземпляр этого класса. Так, из представленных ниже трех операторов первый не верен, поскольку обращается непосредственно к Аггау< Т>::роо1, а обращения к Array<char>::pool и Array<int>::pool sz являются корректными:

cout Array<T>::роо1 endl; Array<char>* ptr = Array<char>::pool; int X = Array<int>::pool sz;

Ошибка правильно правильно



Нешаблонная функция может манипулировать объектами специализированных экземпляров шаблонов классов, тогда как шаблонная функция может использовать объекты либо конкретного экземпляра, либо общего шаблона класса. В приведенном ниже примере foo - нешаблонная функция; следовательно, она может работать с объектами специализированного экземпляра (в данном случае Army<int>) класса Array. Шаблонная функция foo2 может манипулировать объектами любого экземпляра класса Array, если они имеют параметры одаого типа (т.е. функция foo2<int> может в качестве аргумента принимать объект типа Array<int>): void foo(Array<int>& Aobj, int size ) :i

Array<int> *ptr = SAobj,-;

r\: ... .

template <class T> extern void foo2 ( Array<T>&, Array<int>& ];

2.12. Обработка исключительных ситуаций

В ANSI/ISO С++ есть стандартный метод обработки исключительных ситуаций, с помощью которого все приложения реагируют на отклонения, возникающие в ходе выполнения программ. Наличие такого метода упрощает работу по созданию приложений и обеспечивает согласованность в их функционировании.

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

Механизмы обработки исключительных ситуаций в С++ синхронны; генерируются исключительные ситуации в пользовательских приложениях через явные операторы throw. Этим они отличаются от асинхронных исключительных ситуаций, генерируемых такими событиями, как нажатие пользователем клавиши на клавиатуре. Асинхронные исключительные ситуации непредсказуемы, т.е. возникают где угодно и когда угодно, и могут обрабатываться с помощью функции signal (см. главу 9).

Рассмотрим пример обработки иркл)Юч;ительной ситуации в С++:

source module: simple exception .С ♦include <iostream.h> j;..;

main( int argc, char* argvl]j .;, ,.

try {

if (argc===l] throw Insufficient no. of argument ; while (-argc > 0)

cout argc : << argv[argc] endl; cout Finish argv[0] endl; return Of ; .

, ], . .... i -r-

catch (const char* msg ) (

cerr exception: msg endl;

cout main: continue here after exceptionXn ; return 1;

Здесь нормальный код функции main заключен в блок try. В этом блоке проверяется значение argc. Если оно равно 1, возникает исключительная ситуация, для генерации которой выполняется оператор throw. Если же значение argc больше 1, то выполняется цикл while, в котором в обратном порядке выводятся все аргументы командной строки, и программа завершается через оператор return 0.

Оператор throw имеет следующий синтаксис: throw <выражение>;

где <выражение> - это любое выражение С++, которое при вычислении дает значение одного из базовых типов данных С++ или объект класса. Значение этого выражения используется для выбора блока-ловушки, которому соответствует тип аргумента или который совместим с типом данных выражения. Если оператор throw выполняется, то остальные операторы в блоке try пропускаются и управление передается в выбранный блок-ловушку.

В функции можно задавать один или несколько блоков-ловушек. Они должны указываться сразу после блока try. Каждый блок-ловушка начинается с ключевого слова catch, за которым следует спецификация типа исключительной ситуации, заключенная в круглые скобки. После спецификации следует один или несколько операторов блока, заключенных в фигурные скобки. Следует отметить, что хотя блок-ловушка выглядит как определение функции, функцией он не является. Это просто набор операторов С++, которые объединены в группу для каждого типа исключительных ситуаций. Исходя из типа исключительной ситуации, оператор throw выбирает блок-ловушку для выполнения, а сам тип исключительной ситуации определяется значением <выражение> оператора throw. Данное значение, как правило, передает дополнительную информацию о генерируемой исключительной ситуации.



1 ... 6 7 8 [ 9 ] 10 11 12 ... 98

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика