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

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


Применение такого синтаксиса обеспечивает вызов функции-деструктора объектов массива для каждого из них. Если этот массив освобождается операцией

delete arrayP;

ТО функция-деструктор вызывается только для первого объекта массива.

Операции new и delete могут перегружаться в классе. В этом случае при выделении объекта такого класса с помощью операции new и освобождении его посредством операции delete используется экземпляр определенных в данном классе операций.

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

В следующем примере объявляются перегруженные операции new и delete в классе date:

class date (

int year, month, day; public:

date (int a, int b, int c), { year=a, month=b, day=c; }; -dateO {};

перегруженная операция new void* operator new (size t siz )

return::new char[siz];

перегруженная операция delete void operator delete (void* ptr) {

::delete ptr;

Перегруженная функция-член new должна принимать аргумент типа slzej, который задает размер выделяемого объекта в байтах. Эта функция возвращает затем адрес вновь выделенного объекта.

Перегруженная функция-член delete должна принимать аргумент void*, который указывает на освобождаемый объект. Эта функция не возвращает никакого значения.

Пользователи могут реализовать тела функций-членов new и delete так, как считают нужным.

2.10. Перегрузка операций

С++ позволяет пользователям определять стандартные встроенные операции для работы с классами. Это дает возможность использовать объекты классов так, как будто они содержат данные, относящиеся к базовому типу. Встроенные операции + , * и [] для объектов классов смысла не имеют, если только пользователи не перегрузят их явно в своих классах.

& ;

<

>

. <=

>=

&=

<<=

->

delete

В таблице показаны знаки операций С++, которые можно перегружать в классах. При этом значение, очередность выполнения, число операндов перегрузкой не отменяются и, следовательно, операции + , * и & могут определяться как унарные или бинарные. Более того, при перегрузке все префиксные и постфиксные операции ++ и - рассматриваются как префиксные.

Все перегруженные функции операций должны принимать в качестве аргумента минимум один объект класса. Они могут объявляться как дружественные функции или как функции-члены. При этом операции и , которые не требуют, чтобы левый операнд был объектом класса, должны определяться как дружественные функции, а операции (] , = , -> , () и += , которые требуют, чтобы левый операнд был объектом класса,- как функции-члены.

Перегрузка операций демонстрируется в следующем примере:

source module: overload.С ♦include <iostream.h> ♦include <string.h> class sarray

int num; char *data;



public: Mj ;>.: ;;,

sarray( const char* str ) ГЛ конструктор

.{ . , ; .

num = strlen(str)+1; data = new char[num]; strcpy ( data, str ) >

-sarrayO { delete data; );

chars operator[) {int idx ) деструктор {

if (idx>=0 && idx<num)

return data(idx]; else

cerr Invalid index: idx endl; return data[0];

const char*-operator=( const char*--stir-)

if (strlen(str)) .

( . . ,

delete data; num = strlen (str).+ l> data = new char[num]; strcpy (data, str ); .

return str;

const sarrays operator=( const sarrays ob)

{ <

rif {istrlen{obj .data))

delete data;

num = strlen(obj.data)+1; data = new char[num]; strcpy (data, obj.data );

).. . . . return obj;,

int operator == ( const char* str )

return (str s& data) ? strcmp(data, str)

int operator < ( const char* str)

return (strcmp(data,str) < 0) ? 1 : 0;

int operator >,j{, const char* str )< Д;-. . .

return {strcmp(data,str) > 0) ? 1 : 0;

fri nd ostreams operator (©streams os, sarrays obj)

return OS (obj.data ? obj.data : Nil ) ;

int main 0 (

sarray A( Hello ), в( world ); cout A: A endl; A = Bad ; A(0] = T;

cout A: A endl; A = B;

COцt , A: A(l] endl;

cout <i: A < Ё: (A < Two ) endl;

return 0;

операция <<

операция =

операция (]

операция =array&

В этом примере определяется класс sarray, который организует массив символов для каждого из своих объектов. Преимущество использования этого класса состоит в том, что каждый из его объектов динамически настраивает свой буфер для хранения любой строки символов. Более того, объектами можно оперировать с помощью операций << , [] , = и < , которые объявлены как перегруженные функции. Все они делают объекты sarray более доступными для понимания и использования, избавляют пользователей от необходимости манипулировать массивом на более низком уровне.

Компиляция и пробное выполнение этой программы дают следующие результаты:

% СС overload.с

% а.out

А: Hello

А: Tad

А: о

А < В: О

2.11. Шаблоны функций и шаблоны классов

Шаблоны функций и шаблоны классов позволяют пользователям создавать родовые функции и классы, работающие с разными типами данных и классами. После их кодирования и тестирования пользователи могут создавать разные экземпляры этих функций и классов для конкретных типов данных и (или) классов. Таким образом, применение шаблонов функций и классов позволяет добиться существенной экономии времени разработчика.



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

Экземпляр шаблона функции или класса создается при первом использовании или при указании адреса шаблона. Он не имеет имени и уничтожается, как только перестает быть нужным.

2.11.1. Шаблоны функций

Синтаксис объявления шаблона функции представлен ниже:

template <список формальных параметров> <возвращаемое значение>

<имя функции> ( <список аргументов> )

<тело>

Шаблон функции, меняющей местами содержимое двух объектов, определяется следующим образом:

template <class т> void swap ( TS left, T& right )

<

T temp = left; left = right; right = temp;

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

main О {

int а = 1, b = 2;

swap(a,b); создает экземпляр swap{int,int)

double aa = 101.0, bb = 25.0;

swap(aa,bb); создает экземпляр swap(double,double)

Список формальных параметров заключается в символы < и >. Он содержит формальные параметры типа, отделенные друг от друга запятыми. Этот список не может быть пустым. Каждый формальный параметр начинается с ключевого слова class, а далее следует идентификатор типа. Например, правильным будет такое объявление: template <class Т, class U> void foo(T*, U);

Следующее определение - неверное, поскольку перед идентификатором типа и нет ключевого слова class:

template <class Т, U> void fool(TS); ошибка. Должно быть class U

Параметр может встречаться в списке только один раз. Представленное далее объявление содержит ошибку, поскольку задает class Г дважды:

template <class Т, class Т> void fool(Т&); ошибка

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

template <class Т, class U> U fool{T&); ошибка

Правильным будет использовать идентификатор типа U в списке аргументов функции:

template <class Т, class U> U fool(T&,U*); нормально

Шаблон функции может объявляться как внешний {extern), статишский (static) или встроенный (inline). Этот спецификатор ставится после списка параметров, перед спецификацией типа возвращаемого значения. Ниже объявляются встроенная и внешняя функции:

template <class Т> inline void foo(T* tobj, int size) {...} template <class T> extern int fooA(T& tobj);

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

template <class Т> Т min(Т tl, Т t2); template <class Т> Т min(T* tl, Т t2, т t3); template <class T> T min(T tl, int t2);

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

template <class Т> т min(Т tl, т t2) ;

template <class U> U min(U tl, U t2); ошибка!

И, наконец, можно определить специализированные шаблонные функции. При установлении порядка вызова функций специализированные функции имеют более высокий приоритет, чем родовые шаблоны функций. Например, в следующей программе в первом вызове min в функции main используется специализированная версия min, которая принимает аргументы типа char*, а второй вызов min создает экземпляр шаблона функции min для данных типа double:

template <class Т> Т min{T tl, Т t2) (

return (tl < t2) ? tl : t2;

специализированная версия minО char* min(char* tl, char* t2) (

return (strcmp(tl,t2) < 0) ? tl : t2;



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

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