CPP FAQ Часть III

Клуб веб-разработчиков PHP HTML MYSQL JS Apache

вопрос 32. Перегрузка инкремента и декремента. Перегрузка new и delete.

_______________________________________________________________________

Перегрузка инкремента и декремента.

___________________________________

Предположим, мы хотим прибавить 1 к объекту с0 класса С. 

Когда компилятор встречает выражение с префиксным инкрементом ++c0, 

он генерирует вызов функции-элемента c0.operator++(), 

прототип которой должен иметь вид: 

C& operator++ ();

Если префиксная форма инкремента реализуется как функция, 

которая не является функцией-членом класса, то, когда компилятор встречает выражение ++c0, 

он генерирует вызов функции operator++(c0). 

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

friend C& operator++(C&);

По соглашению, принятому в С++, когда компилятор встречает выражение постфиксной 

формы инкремента c0++, он генерирует вызов функции с0.operator++(0), 

прототипом которой является 

C& operator++(int).

Фиктивный параметр int никогда не используется, а лишь служит признаком того, 

что функция вызывается для выполнения операции ++ или -- в постфиксном варианте. 

Если постфиксная форма инкремента реализуется как функция, которая не является 

функцией-членом класса, то, когда компилятор встречает выражение c0++, он генерирует 

вызов функции operator++(c0, 0). Прототип такой функции должен быть объявлен в 

классе С как дружественный: 

friend C& operator++(C&, int);

Перегрузка new и delete.

_______________________

Имеется возможность перегрузить new и delete. 

Это можно сделать в том случае, если необходимо использовать какой-то особый способ 

выделения памяти. Например, нужно выделять память и, в случае отсутствия её, создавать 

дисковый файл, в который можно записывать информацию. Какой бы ни была причина, 

осуществить такую перегрузку очень просто.

Для перегрузки операторов new и delete может использоваться следующий формат:

void* operator new(size_t размер){

     код оператора

     return указатель_на_память;

void operator delete(void* p){

     код оператора

}

Параметр размер будет содержать число в байтах, которое необходимо выделить для 

размещения объекта. Это  значение будет сформировано автоматически. У параметра 

размер тип данных size_t. Данный тип - это псевдоним, под которым скрывается unsigned int. 

В прототипе оператора new можно указать дополнительные параметры, которые будут 

передаваться  при вызове new. Самое главное, чтобы на первом месте в обьявлении 

функции находился параметр типа size_t. Перегруженная функция new должна возвращать 

указатель  на  выделенную память.  По отношению к классу перегруженный оператор new 

будет статической функцией-членом.

Функция delete получает указатель на область памяти, которую необходимо освободить. 

Она обязана освободить эту память. Как в new, так и в delete можно передавать 

дополнительные параметры. Перегруженный оператор delete - статическая функция класса.

Для перегрузки операторов new [] и delete [] может использоваться следующий формат:

void* operator new[](size_t размер){

     код оператора

     return указатель_на_память;

void operator delete[](void* p){

     код оператора

}

Всё вышесказанное о new и delete верно и по отношению к new [] , delete []. 

 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

вопрос 33. Инкапсуляция.

________________________

Инкапсуляция - это механизм, который объединяет данные и методы, манипулирующие 

этими данными, и защищает и то, и другое от внешнего вмешательства или неправильного 

использования. Когда методы и данные объединяются таким способом, создается объект.

Можно сказать, что инкапсуляция подразумевает под собой скрытие данных (data hiding), 

что позволяет защитить эти данные. 

Cуть инкапсуляции можно определить следующим образом: 

Переменные состояния объекта скрыты от внешнего мира. 

Изменение состояния объекта (его переменных) возможно 

ТОЛЬКО с помощью его методов (операций). 

 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

вопрос 34. Наследование. Определение, механизм, назначение.

___________________________________________________________

Наследование - это процесс, посредством которого, один объект может наследовать 

свойства другого объекта и добавлять к ним черты, характерные только для него.

Итак, рассмотрев теоретические вопросы, переходим к практике. 

Класс можно сделать производным от существующего с использованием следующей формы: 

class имя_класса:

(public| protected| private) имя_базового_класса

   {

объяления членов

   };

Синтаксис описания класса Вам уже знаком. 

А для создания наследника от базового класса необходимо после имени класса поставить 

двоеточие, записать спецификатор доступа и указать родителя (т.е. базовый класс).

Теперь, давайте, обобщим правила доступа для классов и объектов закрытых, 

защищенных и открытых частей описания класса. 

1. Элементы, объявленные как закрытые (private), могут использоваться любыми 

   функциями-членами своего класса. 

2. Элементы, объявленные как защищенные (protected), могут использоваться любыми 

   функциями-членами своего класса, а также функциями-членами производных классов. 

3. Элементы, объявленные как открытые (public), могут использоваться любой 

   функцией базового или производного класса. К ним, также, возможно обратиться 

   через экземпляры класса. 

4. Когда класс используется как открытый базовый класс, его открытые элементы 

   становятся открытыми элементами производного класса, а защищенные элементы 

   становятся защищенными элементами производного класса. 

5. Когда класс используется как закрытый базовый класс, его открытые и защищенные 

   элементы становятся закрытыми элементами производного класса. 

6. Когда класс используется как защищенный базовый класс, его открытые и защищенные 

   элементы становятся защищенными элементами производного класса. 

 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

вопрос 35. Статические члены данных.

____________________________________

Модификатор static сообщает компилятору о необходимости статического выделения памяти

для переменной или функции. При таком определении переменная существует в течении

всего времени выполнения программы. 

При объявлении статических данных - элементов класса, элементы класса становятся

доступными для всех объектов класса.

Чтобы создать статический элемент данных, необходимо не только объявить его в классе,

но также определить его в этом же модуле, как если бы это была глобальная переменная.

Член класса,  в котором объект является экземпляром класса, может быть упомянут как

class::member или object.member Например:

class Study{

public:

static long number;

Study(){++number;}

//...

};

long Study::number=0;

Пример объявления статической функции - элемента класса. Такая функция может обратиться 

к другому члену класса только в том случае, если он объявлен как статический.

Функция не может использовать ключевое слово this, и в отличии от большинства

функций-членов класса она не допускает скрытый указатель this. Цель статической

функций-члена заключается в создании способа обращения к статическим данным-членам.

 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

вопрос 36. Указатели и массивы.

_______________________________

В С++ существует тесная связь между указателями и массивами. 

Любой доступ к элементу массива, осуществляемый операцией индексирования, 

может быть выполнен при помощи указателя. 

Запись a[i] отсылает нас к i-му элементу массива. 

Если pa есть указатель на int, т.е. определен как int *pa; 

то в результате присваивания pa=&a[0]; pa будет указывать на нулевой элемент а; 

иначе говоря, ра будет содержать адрес элемента а[0]. 

Теперь присваивание

x=*pa;

будет копировать содержимое a[0] в х. 

Если ра указывает на некоторый элемент массива, то ра+1 по определению указывает 

на следующий элемент, ра+i - на i-ый элемент после ра, а ра-i - на i-ый элемент перед ра. 

Таким образом, если ра указывает на а[0], то *(ра+1) есть содержимое а[1], 

pa+i - адрес а[i], a *(pa+i) - содержимое a[i].

По определению имя масива - это адрес его нулевого элемента. 

После присваивания  pa=&a[0]; pa и а имеют одно и то же значение.

Поскольку имя массива есть не что иное, как адрес его начального элемента, 

присваивание ра=&a[0]; можно также записать в следующем виде: ра=a;

Еще более удивительно то, что а[i] можно записать как *(a+i). 

Встречая запись a[i], компилятор сразу преобразует ее в * (а+i); 

указанные две формы записи эквивалентны.

 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

вопрос 37. Массивы.

___________________

Массив — это последовательная группа ячеек памяти, имеющих одинаковое имя и одинаковый тип.

Объявление массивов.

Массивы занимают область в памяти. Программист указывает тип каждого элемента, 

количество элементов, требуемое каждым массивом, и компилятор может зарезервировать 

соответствующий объем памяти. Чтобы указать компилятору зарезервировать память для 6 

элементов массива целых чисел A, используется объявление

int A[6];

Если размер массива не указан в объявлении со списком инициализации, 

то количество элементов массива будет равно количеству элементов в 

списке начальных значений. Например, объявление

int n[ ] = {1, 2, 3, 4, 5};

создало бы массив из пяти элементов.

 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

вопрос 38. Потоки в С++.

________________________

Потоки ввода-вывода.

Поток определяется как последовательность байтов (символов) 

и с точки зрения программы не зависит от устройств, 

с которыми ведется обмен данными (файл на диске, принтер, клавиатура, дисплей и т.п.). 

Описанные в файле iostream.h средства ввода-вывода обеспечивают программиста 

механизмами для извлечения данных из потоков и для включения (помещения) данных в потоки. 

При обмене с потоком часто используется 

вспомогательный участок основной памяти - буфер потока. 

В буфер потока помещаются выводимые программой данные перед тем, как они будут 

переданы внешнему устройству. При вводе данных они вначале помещаются в буфер и 

только затем передаются в область памяти выполняемой программы. 

Использование буфера повышает скорость передачи данных, т.к. реальные пересылки 

осуществляются только тогда, когда буфер уже заполнен (при выводе) или пуст (при вводе). 

Предопределенные потоки.

Библиотека ввода-вывода имеет 4 предопределенных объекта-потока, 

ассоциированных со стандартным вводом и выводом: 

cin - объект класса istream, связанный со стандартным буферизированным входным потоком 

      (обычно с клавиатурой); 

cout - объект класса ostream, связанный со стандартным буферизированным выходным потоком 

       (обычно с дисплеем); 

cerr - объект класса ostream, связанный со стандартным небуферизированным выходным потоком 

       (обычно с дисплеем), в который направляются сообщения об ошибках; 

clog - то же, что cerr, но буферизирован. 

Операции помещения в поток и извлечения из потока.

Библиотека потоков С++ предусматривает два основных класса для ввода и вывода:

istream и ostream. Класс ostream использует для вывода переопределенную операцию 

левого сдвига (<<), которую называют операцией помещения в поток. Класс istream 

использует для ввода переопределенную операцию правого сдвига (>>), которую 

называют операцией извлечения из потока. 

 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

13:36
FF
RSS
Нет комментариев. Ваш будет первым!