CPP FAQ Часть II

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

вопрос 15. Определение структур. Указатели на структуру.

________________________________________________________

Структура - это составной тип данных, построенный с использованием других типов.  

Структура состоит из полей. Поля (элементы структуры) - переменные или массивы 

стандартного типа (int, char и т.п) или другие, ранее описанные структуры. 

Описанный тип данных можно использовать для объявления переменных типа структур. 

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

В одной программе может быть множество разных структур. 

Из структур можно организовывать массивы. 

Объявление структуры осуществляется с помощью ключевого слова struct, 

за которым идет ее имя и далее список элементов, заключенных в фигурные скобки: 

 struct [имя] { 

               тип_элемента_1 имя_элемента_1;

               тип_элемента_2 имя_элемента_2;

                    ...

               тип_элемента_n имя_элемента_n;

     };

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

Именем элемента может быть любой идентификатор. Через запятую можно записывать несколько 

идентификаторов одного типа. Элементы одной и той же структуры должны иметь уникальные 

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

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

struct date { int day, month, year; };

Переменные структуры объявляются так же, как переменные других типов. Например, 

date days;

Указатели на структуру.

_______________________

Имя структуры обладает всеми правами имен типов, 

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

имя_структуры *имя_указателя на структуру;

для доступа к элементам структуры мы использовали операцию точка (.). 

Операция точка обращается к элементу структуры по имени переменной объекта. 

Но, если у нас определен указатель на структуру, то появляется еще одна возможность доступа

к элементам структуры. Ее обеспечивает оператор стрелка (->).

Формат соответствующего выражения следующий: 

имя_указателя->имя_элемента_структуры

Выражение birthday->month эквивалентно (*birthday).month, 

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

Скобки нужны, т.к. оператор точка имеет более высокий приоритет, 

чем оператор разыменования указателя (*). 

Cсылки  на структуру.

_____________________

Как и для других объектов, для структур могут быть определены ссылки: 

имя_структуры &имя_ссылки_на_структуру инициализатор;

Например, для переменной my_date можно, так ввести ссылку: 

Date &now = my_date; 

После такого определения now является синонимом имени пременной my_date.

Для доступа к элементам структуры используется оператор точка. 

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

элементу month переменной my_date типа Date. 

my_date.month      //по имени переменной

now.month          // по ссылке

birthday->month    // через указатель

(*birthday).month  // через разыменованный указатель

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

вопрос 16. Поиск в массивах. Сортировка.

________________________________________

Поиск в массивах.

_________________

Линейный поиск сравнивает каждый элемент массива с ключом поиска. 

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

первым элементом массива. Но в среднем, программа должна сравнить с ключом 

поиска половину элементов массива. 

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

Однако, для больших массивов линейный поиска неэффективен. Если массив отсортирован, 

можно использовать высокоэффективный метод двоичного поиска. 

Алгоритм двоичного поиска исключает половину еще непроверенных элементов массива после

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

сравнивает его с ключом поиска. Если они равны, то ключ поиска найден и выдается 

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

Если ключ поиска меньше, чем средний элемент массива, то дальнейший поиск осуществляется в 

первой половине массива, а если больше, то во второй половине.

Поиск продолжается до тех пор, пока ключ поиска не станет равным среднему элементу 

или пока оставшийся подмассив содержит хотя бы один элемент, не равный ключу поиска. 

Сортировка.

____________

Сортировка подробно описана в вопросе номер 10.

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

вопрос 17. Определение функции. return. Прототипы функций.

__________________________________________________________

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

Формально это выглядит так: 

  заголовок_функции 

{

инструкции

}

Все, что стоит перед первой фигурной скобкой, составляет заголовок определения функции,

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

Заголовок функции — это: 

тип имя(список_объявлений_параметров)

Спецификация типа, стоящая перед именем функции, является возвращаемым ти­пом.

Он определяет тип значения, возвращаемого функцией (если оно вообще воз­вращается). 

Имена функций подчиняются тем же ограничениям, что и имена переменных. 

return.

_______

Инструкция return возвращает управление из тела функции. При обработке компилятором

инструкции return выполнение функции завершается, а все ее последующие инструкции

не выполняются.

Синтаксис:

return[expression];

При задании инструкции  return с аргументом expression (который может быть выражением)

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

показывают что аргумент не обязателен. Если аргумент опущен, инструкция  return

просто выполняет выход из функции.

Прототипы функций.

__________________

Прототип - определение функции, содержащее полную информацию о количестве и типах

параметров, а также о типе возвращаемого значения.

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

вопрос 18. Работа со строками в С++.

____________________________________

Строка определяется как последовательность (массив) символов, заключенных в двойные

кавычки. Признаком конца строки является управляющий символ нуль-терминатор \0.

В описании строки должна быть указана максимально возможная длинна плюс один

(для нуль-терминатора). Объем памяти, выделенный для строки, остается неизменным

в облости ее видимости, но все символы, стоящие после признака конца строки, игнорируются.

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

char str[50];

char str_start[]="START";

Char start[7]={'S','T','A','R','T',' ','\0'};

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

вопрос 19. Многомерные массивы. Двумерные массивы. Многомерные динамические массивы.

____________________________________________________________________________________

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

массив. Описание двухмерного массива отличается от одномерного толко наличием ещо

одного значения длинны в квадратных скобках. 

Первое значение - количество строк в таблице.

Второе значение - количество столбцов.

В памяти компьютера элементы распологаются построчно: сначала первая строка,

затем вторая и т.д. Каждый элемент массива имеет два индекса: номер столбца и

номер строки, в которых он находится. Все индексы начинаются с нуля.

Пример:

int a[3][4];

a[0][0]=1; // 1-й элемент таблицы

a[0][i]=i; // i-й элемент первой строки

a[j][i]=j*i; // i-й элемент j-й строки

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

При этом первым индексом будет номер таблицы, вторым - номер строки, третьим - номер

столбца.

int tables[2][3][4]; //2 таблицы размером 3х4

Многомерные динамические массивы.

_________________________________

1. Определяем переменную array как адрес массива адресов: 

float **array;

2. Выделяем область памяти для массива из n указателей на тип float 

и присваиваем адрес начала этой памяти указателю аrray. 

Оператор, выполняющий эти действия выглядит так: 

array = new float* [n];

3. В цикле пробегаем по массиву адресов array[], 

присваивая каждому указателю array[i] адрес вновь выделяемой памяти 

под массив из n чисел типа float.

for(int i=0;i<n;i++){

array[i] = new float[n];

}

Захваченную для массива память следует вновь возвращать в распоряжение операционной 

системы. То есть освождать с помощью операции delete. 

for(int i=0;i<n;i++){

delete [] array[i];

}

delete [] array;

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

вопрос 20. Шаблоны функций. Шаблоны классов.

_____________________________________________

С помощью шаблонов функций языка С++ можно создать единственное общее определение 

функции, использующееся с различными типами данных. 

Используя шаблон языка С++, можно создать единственное определение, 

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

или любого подходящего другого типа. Такой шаблон выглядит следующим образом: 

template <typename T> T Abs (T N)

{

  return N < 0 ? -N : N;

}

При определении шаблона нужно использовать спецификаторы template и typename 

вместе с угловыми скобками, как показано в приведенном выше примере. 

Для параметра типа Т можно использовать любой корректный идентификатор имени, 

а в угловые скобки можно включать несколько параметров типа. 

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

template <typename T1, typename T2> T2 Max(T1 A , T2 B)

{

   return A > B ? A : B;

}

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

________________

Общая форма объявления параметризованного (обобщенного) класса. 

template <class Tтип_данных> class имя_класса { 

//....описание класса....... 

}; 

Рассомотрим это объявление. 

Здесь Tтип_данных представляет собой имя типа шаблона, которое в каждом случае 

конкретезации будет замещаться фактическим типом данных.

При необходимости, можно определить более одного параметризовнного типа данных, 

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

несколько аргументов шаблона. 

Заметим, что в пределах определения класса имя Tтип_данных можно использовать в любом месте.

Вы можете создать конкретную реализацию этого класса, используя следующий синтаксис: 

имя_класса <тип_данных> объект; 

В приведенном синтаксисе тип_данных представляет собою имя типа данных, 

над которыми фактически оперирует класс, и заменяет собой переменную Tтип_данных

Практический пример:

template <class T> class TestClass {

private:

T tempo;

public:

TestClass(){tempo=0;}

        T testFunc();

};

//Так как метод реализован вне класса, 

//используем явное упоминание template

template <class T>

T TestClass<T>::testFunc() {

    cout<<"Type's size is: "<<sizeof(tempo)<<endl;

return tempo;

}

void main()

{

//создадим конкретные экземпляры класса TestClass

//char

TestClass<char> ClassChar;

ClassChar.testFunc();

//int

TestClass<int> ClassInt;

ClassInt.testFunc();

//double

TestClass<double> ClassDouble;

ClassDouble.testFunc();

}

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

вопрос 21. Файловый ввод-вывод с применением потоков.

_____________________________________________________

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

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

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

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

Чтобы можно было использовать потоковые классы, 

а соответственно, их данные и методы необходимо включить в программу 

нужный заголовочный файл: 

iostream.h - для классов ios, istream, ostream, stream; 

fstream.h - для классов ifstream, ofstream, fstream; 

Бибилиотека потоков содержит три класса, 

предназначенных для ввода и вовода в файлы: 

ofstream - для вывода (записи) данных в файл; (наследник ostream)

ifstream - для ввода (чтения) данных из файла; (наследник istream)

fstream - для чтения и для записи данных (двунаправленный обмен, наследник iostream).

ofstream outf; // определяется выходной файловый поток

ifstream inf;  // определяется входной файловый поток

fstream iof;   // определяется файловый поток для ввода и вывода

"Присоединить" файловый поток к конкретному файлу можно с помощью компонентной 

функции open(). Функция open() унаследована каждым из файловых классов ofstream, 

ifstream, fstream от класса fstreambase. 

Формат функции : 

void open(const char *fileName, int mode = значение_по_умолчанию,

          int protection = значение_по_умолчанию);

fileName - имя уже существующего или создаваемого заново файла.

Параметр mode - определят режим работы с откываемым файлом (например, только запись).

Флаги определяются в файле ios.h (см. перечислимая константа open_mode). 

enum open_mode { 

      in        = 0x01, // открыть только для чтения

      out       = 0x02, // открыть только для записи

      ate       = 0x04, // установить указатель на конец файла

      app       = 0x08, // дописывать данные в конец файла

      trunc     = 0x10, // усечь файл до нулевой длины

      nocreate  = 0x20, // если файл не существует, ошибка открытия

      noreplace = 0x40, // если файл уже существует, ошибка открытия

      binary    = 0x80  // открыть файл для двоичного обмена

};

Пример:

outf.open("d:\\temp\\file1.txt");

inf.open("file2.txt");

iof.open("file3", ios::app);

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

вопрос 22. Форматированный вывод.

_________________________________

Чтобы, например, указать ширину полей, левое или правое выравнивание и т.д. 

можно использовать printf(), а можно сделать то же самое при помощи средств 

форматирования ввода/вывода языка С++. Существуют два способа форматирования 

ввода/вывода, которые мы по очереди рассмотрим 

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

форматирования, которые перечислены в классе ios_base

enum {  skipws     = 0x0001,

        left       = 0x0002,

        right      = 0x0004,

        internal   = 0x0008,

        dec        = 0x0010,

        oct        = 0x0020,

        hex        = 0x0040,

        showbase   = 0x0080,

        showpoint  = 0x0100,

        uppercase  = 0x0200,

        showpos    = 0x0400,

        scientific = 0x0800,

        fixed      = 0x1000,

        unitbuf    = 0x2000,

        stdio      = 0x4000        

};

Рассмотрим что делают перечисленные выше флаги.

Флаг                                             Описание 

____________________________________________________________________________________________

skipws Следующие в начале символы-разделители 

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

при выполнении ввода отбрасываются. 

____________________________________________________________________________________________

left Осуществляется ввод с левым выравниванием 

____________________________________________________________________________________________

right Осуществляется ввод с правым выравниванием (по умолчанию) 

____________________________________________________________________________________________

internal Знак или префикс системы счисления выравнивает слева,

число выравнивает справа 

____________________________________________________________________________________________

dec Численные значения выводятся в десятичной форме 

____________________________________________________________________________________________

oct Численные значения выводятся в восьмеричной форме 

____________________________________________________________________________________________

hex Численные значения выводятся в шестнадцатиричной форме 

____________________________________________________________________________________________

showbase Позволяет при выводе указывать числовую базу 

(десятичную, восьмеричную, шестнадцатиричную) 

____________________________________________________________________________________________

showpoint Приводит к выводу десятичной запятой и нулей справа для 

всех чисел с плавающей запятой вне зависимости, 

нужно это или нет 

____________________________________________________________________________________________

uppercase При выводе чисел с плавающей точкой при использовании 

экспоненциальной формы выводится большая буква E. 

Также при выводе чисел в шестнадцатиричной форме символ 'x' 

выводится в верхнем регистре. 

____________________________________________________________________________________________

showpos Приводит к тому, что перед положительным числом будет 

выводится знак "+" 

____________________________________________________________________________________________

scientific Числа с плавающей запятой выводятся с 

использованием научной нотации 

____________________________________________________________________________________________

fixed Числа с плавающей запятой выводятся в нормальной нотации 

____________________________________________________________________________________________

unitbuf При каждой операции вставки вывода данные немедленно

заносится в поток 

____________________________________________________________________________________________

Что делают флаги мы рассмотрели. 

Теперь необходимо познакомиться с функциями, которые устанавливают и сбрасывают эти флаги.

Первая функция, которую мы рассмотрим, - это функция setf(), 

используемая для установки флагов

long setf(long flags);

Функция принимает в качестве параметра рассмотренные выше флаг или флаги, 

соединенные между собой при помощи побитового ИЛИ. 

Она возвращает предыдущее значение флага. Рассмотрим пример:

cout.setf(ios::hex);

cout.setf(ios::showpos);

cout<<123<<" "<<123.45<<"\n";

cout<<67<<" "<<678.9<<"\n";

выведет на экран

7b +123.45

43 +678.9

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

cout.setf(ios::hex | ios::showpos);

cout<<123<<" "<<123.45<<"\n";

cout<<67<<" "<<678.9<<"\n";

Для отключения установленных флагов нужно использовать функцию unsetf(). 

Она имеет следующий прототип:

long unsetf(long flags);

Функция возвращает значение предыдущей установки флага и сбрасывает флаги, 

определяемые параметром flags. Пример:

cout.setf(ios::showpos | ios::hex);

cout<<123<<" "<<123.45<<"\n";

cout.unsetf(ios::showpos | ios::hex);

cout<<123<<" "<<123.45<<"\n";

выведет на экран

7b +123.45

123 123.45

Кроме флага форматирования также можно установить ширину поля потока, 

символ для заполнения и число цифр после десятичной запятой. 

Для этого используются следующие функции:

int width(int len);

char fill(char ch);

int precision(int num);

А теперь мы переходим к рассмотрению второго способа форматирования ввода/вывода. 

Второй способ - это использование манипуляторов.

Манипуляторы являются специальными функциями, которые позволяют изменять флаги потока. 

Существуют манипуляторы с параметрами и без. Если Вы используете манипуляторы с 

параметрами, подключите файл iomanip.h

Рассмотрим манипуляторы без параметров:

ends - помещает в выходной поток нулевой символ; 

endl - помещает в выходной поток символ конца строки и вызывает метод flush; 

flush - выгружает буфер потока; 

dec, hex, oct - устанавливают основания 10, 16 и 8 соответственно; 

ws - заставляет игнорировать ведущие пробелы при вводе. 

Манипуляторы с параметрами

setbase(int b)  - задает основание системы счисления; 

resetiosflags(long f)  - сбрасывает флаги, указанные в параметре; 

setiosflags(long f)  - устанавливает флаги, указанные в параметре; 

setfill(int ch)  - задает заполняющий символ; 

setprecision(int n)  - задает точность вещественных чисел; 

setw(int n)  - задает ширину поля. 

Использование манипуляторов рассмотрим на примере

cout<<setw(5)<<setfill('*')<<22<<endl;

cout<<hex<<11<<endl;

выведет на экран

***22

b

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

вопрос 23. Операторы свободной памяти new и delete.

___________________________________________________

унарные операторы new и delete служат для управления свободной памятью. 

В С++ оператор new принимает следующие формы:

                        new имя_типа;

                        new имя_типа (инициализатор);

                        new имя_типа [выражение];

В каждом случае происходит по крайней мере два эффекта. 

Во-первых, выделяется надлежащий объем свободной памяти для хранения указанного типа. 

Во-вторых, возвращается базовый адрес объекта (в качестве значения оператора new ). 

Когда память недоступна, оператор new возвращает значение 0 (NULL). Следовательно, 

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

Рассмотрим следующий пример использования оператора new: 

int  *p, *q;

p=new int (5);    //выделили память и инициализировали

q=new int [10];   //получаем массив от q[0] до q[9]

Оператор delete уничтожает объект, созданный с помощью new, 

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

Оператор delete может принимать следующие формы: 

delete выражение;

delete [] выражение;

Первая форма используется, если соответствующее выражение new размещало не массив. 

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

что изначально размещался массив объектов. 

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

вопрос 24. Ввод-вывод в С.

__________________________

Файл заголовков: stdio.h

Вывод.

К наиболее интересным функциям вывода данных в языке С относится функция printf();

Она предназначена для форматированного вывода данных.

Чтобы вывести некоторое сообщение на экран монитора, достаточно испоьзовать вызов функции:

prinf("Интересное сообщение\n");

Обычно printf служит для вывода значений переменных. Первым аргументом служит строка

форматов, а последующими, если они есть, - выводимые объекты.

Строка форматов может включать обычные символы, просто копируемые при выводе и

спецификации преоброзования, которые начинаются со знака %, за ним следует 

символ преоброзования. Пример:

printf("Значения  a, b, c равны:%d,%d,%d \n",a,b,c);

Ввод.

Функция scanf() обеспечивает форматированный ввод данных.

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

Для этого перед параметром ставится знак & - символ взятия адреса переменной.

Рассмотрим пример ввода целого числа i:

scanf("%d",i);

Спецификаторы формата для функций printf(), scanf();

%c -Ввод одного символа;

%d -Ввод целого числа как десятичного;

%u -Ввод беззнакового целого числа как десятичного;

%o -Ввод целого числа как восмеричного;

%x -Ввод целого числа как шестнадцатиричного;

%e,%f,%g-Ввод вещественного числа;

%s -Ввод строки текста до ближайщего пробела, табуляции или конца строки.

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

вопрос 25. Аргументы командной строки.

______________________________________

Имеется возможность передачи аргументов в функцию main из командной строки. 

Для этого нужно в список параметров функции main включить параметры 

int argc и char *argv[]  (названия общепринятые, но необязательные).

Параметр argc получает значение, равное количеству аргументов командной строки. 

Параметр argv - это массив строк, в который помещаются значения аргументов командной 

строки (argv[0] - полный путь к самой программе). 

Обычно аргументы командной строки используются для задания опций 

выполнения программы и передачи программе имен файлов. 

Пример:

int main(int argc, char *argv[]){

for(int i=0;i<argc;i++){

cout<<argv[i]<<endl;

}

return 0;

}

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

вопрос 26. Объектно-ориентированное программирование.

_____________________________________________________

ООП позволяет разложить проблему на связанные между собой задачи. 

Каждая проблема  становится самостоятельным объектом, содержащим свои собственные 

коды и данные, которые относятся к этому объекту. В этом случае исходная задача в 

целом  упрощается,  и  программист получает возможность оперировать с большими по 

объему программами. 

С точки зрения программирования подобный подход значительно упрощает 

разработку и отладку программ. 

Объект - это совокупность отдельных информационных элементов и функций, 

которые им оперируют.

Объект состоит из следующих трех частей: 

имя объекта; 

состояние (переменные состояния); 

методы (операции). 

Возможность управлять состояниями объекта посредством вызова методов в итоге и определяет 

поведение объекта. Эту совокупность методов часто называют интерфейсом объекта. 

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

Класс (class) - это группа данных и методов (функций) для работы с этими данными.

Объект (object)- это конкретная реализация, экземпляр класса. 

В программировании отношения объекта и класса можно сравнить с описанием переменной, 

где сама переменная (объект) является экземпляром какого-либо типа данных (класса). 

Методы (methods)- это функции , принадлежащие классу.

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

вопрос 27. Классы. Указатель this.

__________________________________

Класс (class) - это группа данных и методов (функций) для работы с этими данными.

Класс языка С++ позволяет определить не только семейство компонентов данных, 

но и функции, работающие с этими данными.

Класс - это механизм для создания объектов.

класс объявляется с помощю ключевого слова class.

Синтаксис объявления класса похож на синтаксис объявления структуры.

Оснавная форма:

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

закрытые функции и переменные класса

public:

открытые функции и переменные класса

}список_объектов;

В объявлении класса список объектов не обязателен.

Функции обявленные в самом классе требуется определить. Для определения функции-члена

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

функции. Это достигается путем написания имени функции вслед за именем класса с двумя

двоеточиями (::). Два двоеточия называются оператором расширения области видимости.

После того как объект класса создан, можно обращаться к открытым членам класса,

используя оператор точка (.).

this.

_____

Ключевое слово this обозначает объявленный неявно указатель на себя. 

Другими словами, при реализации функций-членов класса, мы работаем с данными так, 

как будто они передаются через указатель this. Особенностью this является то, что 

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

например, это то же самое, как если бы в классе Test неявно объявлялся закрытый 

член Test* const this. Заметим, что указатель this изменить нельзя. 

Обычно указатель this используется неявно, но в некоторых ситуациях желательно 

его явное использование, причем, использование this не отличается от использования

любого другого указателя.

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

вопрос 28. Конструкторы. Конструкторы копирования.Деструкторы.

______________________________________________________________

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

Сделать это непосредственно в определении класса нельзя, например, следующее описание 

приведет к ошибке компиляции: 

class my_Time {

public:

int hours = 0; // ошибка

int minutes = 0; // ошибка

};

Для присваивания начальных значений элементам класса в языке С++ есть такой 

механизм как конструкторы.

Конструктор (construct - создавать) - это специальная функция-член класса с тем же именем,

что и класс. Таким образом, конструктор - это функция, но в соответствии с синтаксисом 

языка С++ для конструктора не определяется тип возвращаемого значения. Нельзя указывать 

даже void (конструктор никогда не возвращает значение). 

Пример конструктора:

имя_класса() 

{  // тело конструктора

}

Конструктор без параметров называют конструктором по умолчанию. 

Для каждого класса может существовать только один конструктор по умолчанию. 

Конструктор копирования.

________________________

Синтаксис конструктора копирования:

имя_класса(const имя_класса & W){

      тело конструктора

  

}

Здесь W является ссылкой на обьект в правой части инициализации. 

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

если для них определены значения по умолчанию.Однако в любом случае 

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

Памятка:

Инициализация возникает в 3х случаях. 

1. Когда один объект инициализирует другой,

2. когда объект передаётся в функцию по значению и

3. когда объект служит в качестве возвращаемого значения функции

Деструкторы.

____________

Деструктор решает задачу, обратную задаче конструктора. 

Деструктор (destruct - разрушать) - это специальная функция-член класса. 

Имя деструктора состоит из символа тильда (~) и имени класса. 

Пример деструктора:

~имя_класса() 

{  // тело деструктора

}

Деструктор класса вызывается при уничтожении объекта - например, 

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

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

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

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

Деструктор не принимает никаких параметров и не возвращает никаких значений. 

Класс может иметь только один деструктор. 

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

вопрос 29. Указатели на объекты. Перегруженные конструкторы.

____________________________________________________________

Указатели на объекты.

_____________________

Как мы знаем в С++ для доступа к членам обьекта через сам обьект используется 

оператор " точка " ( . )

Итак если мы работаем с обьектом класса необходимо использовать оператор " точка " ( . ) ,

если же работа происходит через указатель на класс то " стрелка " ( -> ) 

единственно правильный выбор !!!

Инкремент ( ++ ) или декремент ( -- ) указателя изменяют его таким образом, 

что он всегда указывает на следующий элемент базового типа. 

Тоже самое и справедливо и для указателей на класс.

Пример:

имя_класса * имя_обекта;//объявляем указатель на объект класса

имя_обекта->элемент_класса;//получаем доступ к членам объекта

Перегруженные конструкторы.

___________________________

Конструктор - тоже функция отсюда следует вывод !!! 

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

которые используются при обычной перегрузке функций .Возникает вопрос , 

а зачем мне собственно говоря перегружать конструктор ? 

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

различные способы инициализации .

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

вопрос 30. Перегрузка операторов.

_________________________________

Язык С++ дает возможность распространить действие практически любой стандартной 

операции на новые типы данных, вводимые пользователем. Сделать это позволяет 

механизм перегрузки стандартных операций. 

С перегрузкой операторов мы сталкиваемся практически с первых занятий. 

Например, операция сложения (+) выполняется для целых чисел, чисел с 

плавающей точкой и с удвоенной точностью совершенно по-разному. 

Тем не менее сложение прекрасно работает с любыми типами - int, float, double 

и многими другими встроенными типами, т.к. операция сложения (+) перегружена в самом С++. 

Чтобы появилась возможность использовать стандартную для языка С++ операцию 

(например, '+' или '*') с необычными для нее данными, необходимо специальным 

образом определить ее новое поведение. 

Механизм перегрузки функций во многом схож с механизмом определения функций. 

Чтобы определить действие некоторой операции для нового пользовательского типа данных, 

нужно описать специальную функцию, называемую "операция-функция" (operator function). 

Формат определения операции-функции: 

тип_возвращаемого_значения operator знак_операции 

(список параметров операции-функции)

{

   тело_операции-функции

}

Например, прототип операции-функции + для моего класса MyClass: 

MyClass operator+(MyClass);

Теперь, чтобы сложить два объекта ob1 и ob2, 

достаточно просто записать выражение ob1 + ob2, 

которое интерпретируется как вызов функции ob1.operator+(ob2). 

Определенная таким образом операция называется перегруженной (по-английски - overload), 

а сам механизм - перегрузкой или расширением действия стандартных операций языка С++. 

Внимание! Операции, которые не могут быть перегружены:

.   ::   ?:    sizeof 

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

вопрос 31. Дружественные функции и классы.

__________________________________________

Иногда необходимо получить прямой доступ к полям-данных класса,

не используя его интерфейс. Т.е. чуть-чуть отступить от правил 

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

Зачем это может понадобиться? Одна из причин может быть следующей, например - 

при доступе к внутренним переменным класса через его функции уменьшается эффективность 

работы за счет затрат на вызов функции. В большинстве случаев это не критично, но не всегда.

В некоторых случаях это может играть существенную роль. Конечно, можно добавить новый метод

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

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

наша функция может оказаться как бы ни у дел. Или, еще один пример, нам необходимо 

получить прямой доступ к внутренним данным двух разных классов. 

Вот здесь-то и возникает проблемка... 

Для решения подобного круга задач в С++ и существует возможность описания функции, 

функции-члена другого класса как дружественной (friend). Класс может предоставлять 

особые привилегии определенным внешним функциям или функциям-членам другого класса. 

Вот эти функции и получили название дружественных. Рассмотрим как работает этот механизм. 

Для описания функции (функции-члена) дружественной тому или иному классу, необходимо 

в описании этого класса объявить дружественную функцию, используя ключевое слово friend. 

Причем, обратите внимание, не играет никакой роли в каком из разделов класса 

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

Если все функции-члены одного класса являются дружественными функциями другого класса, 

то это можно записать как: 

friend class имя_класса; 

Итак, если функция или функция-член объявлены как дружественные, 

то такие функции или функции-члены такого класса могут осуществлять 

непосредственный доступ ко всем (private, protected, public) данным 

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

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

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

_______________________________________________________________________

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

___________________________________

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

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

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

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

C& operator++ ();

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

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

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

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

friend C& operator++(C&);

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

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

п

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