C++. Введение в классы и объекты

Содержание

Слайд 2

Статические поля класса Пример 7: // main.cpp #include using namespace std;

Статические поля класса
Пример 7: // main.cpp
#include
using namespace std;
class TPoint

{ double x,y;
public:
static int N; //количество точек
TPoint(double x1=0.0,double y1=0.0)
{ N++; x = x1; y = y1;}
};
int TPoint::N=0; //определение и инициализация статич. поля
int main(void)
{ TPoint A(1.0,2.0); TPoint B(4.0,5.0);
TPoint *C = new TPoint(7.0,8.0);
cout << "Определены " << TPoint::N << " точки\n";
cout << "Определены " << A.N << " точки\n";
cout << "Определены " << C->N << " точки\n";
delete C;}
Слайд 3

Cтатические поля класса объявляются внутри класса с использованием ключевого слова static.

Cтатические поля класса объявляются внутри класса с использованием ключевого слова static.

Специфика статических полей:
а) размещаются в статической области памяти на стадии компиляции (когда еще не создано ни одного объекта!) независимо от того, где создается сам объект.
б) существуют в единственном экземпляре (то есть компилятор выделяет под нее память только один раз!) независимо от того, сколько создано объектов. Это означает, что для полей класса с ключевым словом static при создании объекта память не резервируется.
Статическое поле класса является общим для всех объектов этого класса. Необходимость в таких переменных продиктована рядом практических соображений, и их использование во многих случаях оправдано. Например, в программе нужно контролировать количество созданных на данный момент объектов определенного класса. В этом случае создается статический член класса, значение которого определяется количеством объектов в работе. 
Для того чтобы компилятор отвел под статическую переменную место в статической памяти ее необходимо определить и инициализировать вне функций и вне объявления класса. Статические переменные независимо от спецификатора доступа определяются и инициализируются одинаково.
Статическая переменная класса по сути является глобальной, заключенной в пространство имен класса , поэтому к public статической переменной можно обращаться посредством имени класса и операции области видимости ( cout << TPoint::N). С другой стороны, формально статическая переменная является членом класса, поэтому ничто не мешает обращаться к ней посредством объекта: cout << A.N << C->N.
Обращение к статической переменной внутри методов класса для программиста ничем не отличается от обращения к обычной переменной, компилятор же подставляет обращение по адресу статической переменной, поэтому статические переменные никогда не должны инициализироваться в конструкторе.
Слайд 4

Статические методы класса Пример 8: // main.cpp #include using namespace std;

Статические методы класса
Пример 8: // main.cpp
#include
using namespace std;
class TPoint

{ double x,y;
static int N;//количество точек
public:
TPoint(double x1=0.0,double y1=0.0)
{ N++; x = x1; y = y1;}
static int& count(){return N;}
};
int TPoint::N; //определение и инициализация
// статического поля (по умолчанию 0)
int main(void)
{ TPoint A(1.0,2.0); TPoint B(4.0,5.0);
TPoint *C = new TPoint(7.0,8.0);
cout << "Определены " << TPoint::count() << " точки\n";
delete C;}
Слайд 5

Статический метод – это по сути глобальная функция, область видимости которой

Статический метод – это по сути глобальная функция, область видимости которой

ограничена именем класса, поэтому (если она public) фактически вызвать ее можно, указывая имя класса и спецификатор области видимости, но формально она является членом класса, поэтому вызывать ее можно также посредством объекта или указателя на объект.
Основные отличия статического метода класса от обычного:
указатель this в статических методах не существует;
Чтобы обратиться к нестатическим полям класса в статическом методе нужно им передать объект как параметр;
Статические методы используются для доступа private или protected static-данным класса (см. пример на слайде).
Слайд 6

Указатель на функцию Объявление указателя на функцию: тип (*имя_указателя)(типы параметров функции)

Указатель на функцию
Объявление указателя на функцию:
тип (*имя_указателя)(типы параметров функции)
Вызов

функции по указателю:
(*имя_указателя)(список фактических параметров)
Пример 9: // main.cpp
#include
using namespace std;
//суммирование двух чисел
float sum(float a, int b)
{ return a + b;}
int main(void)
{ float (*ptr)(float, int); // описание указателя на функцию
ptr = sum; // присвоение указателю адреса функции
float x = sum(0.5, 1); // вызов функции по имени
float y = (*ptr)(1.5, 2); // вызов функции по указателю
cout << "x = " << x << ' ' << "y = " << y << endl;
}
Слайд 7

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

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

с соответствующими типами в определении функции, на которую ставится указатель.
Присвоение указателю на функцию адреса функции не требует операции взятие адреса (&), поскольку имя функции само по себе обозначает этот адрес.
Слайд 8

Указатель на функцию как параметр функции Пример 10: //Нахождение корня нелинейного

Указатель на функцию как параметр функции
Пример 10: //Нахождение корня нелинейного

уравнения методом
// деления пополам
#include
#include
using namespace std;
double func(double x);
double bisect(double a, double b, double eps,
double (*f)(double))
{ double c, y;
do { c = 0.5*(a+b); y = f(c);
if (fabs(y) < eps) break; //корень найден. Выход из цикла
// Если на концах отрезка [a, c] функция имеет разные знаки
if (f(a)*y < 0.0) b = c; // значит, корень здесь.
// Переносим точку b в точку c
// В противном случае:
else a = c; // переносим точку а в точку с
// Продолжаем, пока отрезок [a, b] не станет мал
}while(fabs(b-a) >= eps);
return c;
}
Слайд 9

Указатель на функцию как параметр функции Продолжение примера 10: int main(void)

Указатель на функцию как параметр функции
Продолжение примера 10:
int main(void)
{ double

a = 0.0, b = 1.5, eps = 1e-5;
cout << bisect(a, b,eps,func)<< endl;
}
double func(double x)
{ return x*x*x - 3*x*x + 3; }
Слайд 10

Функция qsort Прототип функции qsort (stdlib.h (С), cstdlib (С++): void qsort(void*

Функция qsort
Прототип функции qsort (stdlib.h (С), cstdlib (С++):
void qsort(void* first, size_t

num, size_t size, 
int (* comp) (const void*, const void*));
Параметры:
first - указатель на первый элемент сортируемого массива;
num - количество элементов в сортируемом массиве, на который ссылается указатель first;
size - размер одного элемента массива в байтах;
comp – указатель на функцию, которая сравнивает два элемента массива. Функция должна иметь следующий прототип:
int compare(const void* v1, const void* v2)
Слайд 11

Функция qsort выполняет сортировку num элементов массива, на который ссылается указатель

Функция qsort выполняет сортировку num элементов массива, на который ссылается указатель first. Для каждого элемента массива

устанавливается размер в байтах, который передается через параметр size. Последний параметр функции qsort— указатель comp на функцию сравнения, которая используется для определения порядка следования элементов в отсортированном массиве.
Функция сравнения (compare) имеет два параметра  - не типизированные указатели (void* v1, void* v2) на элементы массива. Эти параметры должны быть приведены к указателям на те типы данных, которые имеют элементы массива. Возвращаемое значение этой функции должно быть отрицательным, положительным или равным нулю.  Если необходимо выполнить сортировку элементов массива по возрастанию, то если *v1  < *v2, тот функция должна вернуть отрицательное значение, если *v1  > *v2, тот функция должна вернуть положительное значение, если *v1  == *v2, тот функция должна вернуть ноль.
Слайд 12

Пример 11. //пример использования функции qsort #include #include using namespace std;

Пример 11.
//пример использования функции qsort
#include
#include
using namespace std;
int vector[] =

{ 14, 10, 11, 19, 2, 25 };
int compare(const void * x1, const void * x2)
{if (*(int*)x1 < *(int*)x2) return -1;
else if (*(int*)x1 > *(int*)x2) return 1;
else return 0;
}
int main ()
{ qsort(vector, 6, sizeof(int), compare);
for ( int i = 0; i < 6; i++)
cout << vector[i] << " ";
return 0;
}
Слайд 13

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

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

классов
}
#include
#include
namespace n1
{ int pow(int x, int y) { return x + y;}
}
namespace n2
{ int pow(int x, int y) { return x - y;}
}
int main()
{ std::cout << n1::pow(2, 1) << std::endl
<< n2::pow(2, 1) << std::endl
<< std::pow(2, 1) << std::endl;
}
Слайд 14

Потоковые классы С++ *

Потоковые классы С++

*

Слайд 15

В С++ ввод-вывод можно организовать с использованием процедурно-ориентированной библиотеки ( в

В С++ ввод-вывод можно организовать с использованием процедурно-ориентированной библиотеки (

в стандарте С++). или объектно-ориентированной библиотеки . В этих библиотеках реализуется концепция ввода-вывода, независимого от устройств. Несмотря на то, что устройства ввода-вывода имеют разные характеристики, система ввода-вывода С++ предоставляет программисту единый удобный интерфейс. Для этого используется абстрактное понятие «поток», относящееся к любому переносу данных от источника к приемнику. Поток – последовательность символов. Программа имеет дело не с устройствами или с файлами, а с потоками. Ввод информации осуществляется из входного потока, вывод программа производит в выходной поток. А уж поток можно связать и с устройством, и с файлом.
В программе поток представлен потоковой переменной определенного типа: в , например, указателем на структуру FILЕ, а в объектами потоковых классов (например, istream, ostream, iostream, …).
Потоки подразделяют на: входные и выходные; из входного потока информация считывается; в выходной поток данные записываются; двунаправленный поток реализует чтение и запись;
В соответствии с особенностями «устройства», к которому «присоединен» поток, их делят на стандартные, файловые и строковые.
Стандартные потоки соответствуют передаче данных «от клавиатуры» и «к экрану». Стандартные потоки бывают только однонаправленными: либо информация только читается из потока, либо – только пишется в поток. Если символы потока размещаются на внешнем носителе данных (диске и т.д.) – это файловый поток. Если символы потока в совокупности образуют символьный массив (строку) в основной памяти, то это строковый поток. Файловые и строковые потоки могут быть и двунаправленными: из потока можно вводить информацию и в тот же поток – выводить.
Слайд 16

Потоки подразделяют на: буферизуемые и не буферизуемые; при обмене с потоком

Потоки подразделяют на: буферизуемые и не буферизуемые; при обмене с потоком

часто используется вспомогательный участок основной памяти – буфер потока; при буферизованном потоке вывод выполняется не на устройство, а в буфер; использование буфера как промежуточной ступени при обменах с внешними устройствами повышает скорость передачи данных, так как реальные пересылки осуществляются только тогда, когда буфер уже заполнен (при выводе) или пуст (при вводе); данные помещаются в буфер, перед тем как они будут переданы к внешнему устройству (при выводе данных) или перед тем, как они будут переданы в область памяти выполняемой программы; заполненный буфер выводится на устройство, как правило, без непосредственного указания в программе; однако программа может потребовать вывести неполный буфер; при вводе буфер обычно заполняется при выполнении первой операции ввода, специально программировать это не требуется; обычно буферизация реализуется по умолчанию, но в библиотеках есть средства, позволяющие управлять назначением буферов.
Потоки подразделяют на: форматируемые и не форматируемые; форматируемость означает, что при операциях ввода-вывода выполняется преобразование информации: при вводе, как правило, преобразование данных из внешнего представления (символьного вида) в двоичное (внутреннее) представление, а при выводе – наоборот; форматирование всегда выполняется для стандартных потоков;
С потоком связывается внутренний указатель, значение которого задает позицию для выполнения следующей операции чтения или записи;
Каждый поток (в том числе и стандартный) в каждый момент времени находится в некотором состоянии; эти состояния называются good, eof , bad, fail, hardfail;
Средства ввода-вывода С++ могут обеспечить последовательный и прямой доступ к данным,
Слайд 17

Стандартные потоки cin – объект класса istream, соответствующий стандартному потоку ввода,

Стандартные потоки
cin – объект класса istream, соответствующий стандартному потоку
ввода, по

умолчанию связан с клавиатурой;
cout – объект класса ostream, соответствующий стандартному
потоку вывода, по умолчанию связан с экраном;
cerr – объект класса ostream, соответствующий стандартному не
буферизованному потоку вывода для ошибок, по умолчанию
связан с экраном;
clog – объект класса ostream, соответствующий стандартному
буферизованному потоку вывода для ошибок, по умолчанию
связан с экраном;
Операции ввода - вывода
>> - операция ввода (чтения) из потока;
<< - операция вывода (записи) в поток;
int k = 5; cout << k; // cout.operator<<(k)

*

Слайд 18

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

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

стандартные потоки (глобальные потоковые объекты, см. слайд).
Вместе с классами потоков и глобальными потоковыми объектами в библиотеке определены операция чтения (ввода) из потока >> и операция записи (вывода ) в поток << .
Эти операции созданы перегрузкой операций побитового сдвига. Операция сдвига влево ‘<<’ перегружена для вывода в поток. Операция сдвига вправо ‘>>’ перегружена для ввода из потока.
В классе ostream, например, определены перегруженные операции:
ostream& operator<< (ostream&, short); //вывод целых
ostream& operator<< (ostream&, int);
ostream& operator<< (ostream&, long);
ostream& operator<< (ostream&, char); //вывод символов
ostream& operator<< (ostream&, double); //вывод вещественных
ostream& operator<< (ostream&, const char *); //вывод строк
и т.д.
Если в программе встретится, например, оператор cout << k; компилятор выполнит:
• сначала определит, что левый аргумент (объект cout) имеет тип ostream, а правый k– тип int;
• в определении класса объекта cout найдет прототип соответствующего метода (функции_операции operator<<()): ostream& operator<< (ostream&, int);
• для объекта cout вызовет метод cout.operator<<(k); в результате работы которого мы увидим на экране число 5; при этом обеспечивается преобразование значения встроенного типа int в строку символов с параметрами форматирования по умолчанию.
Аналогично происходит работа со стандартным потоком ввода через объект cin, только возвращаемым значением должны быть ссылка на поток ввода istream &.
Слайд 19

Стандартные потоки. Флаги форматирования

Стандартные потоки. Флаги форматирования

Слайд 20

Стандартные потоки. Флаги форматирования

Стандартные потоки. Флаги форматирования

Слайд 21

Стандартные потоки. Методы работы с флагами

Стандартные потоки. Методы работы с флагами

Слайд 22

Стандартные потоки. Примеры использования флагов и методов класса IOS

Стандартные потоки. Примеры использования флагов и методов класса IOS

Слайд 23

Стандартные потоки. Примеры использования флагов и методов класса IOS

Стандартные потоки. Примеры использования флагов и методов класса IOS

Слайд 24

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

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

можно использовать параметры форматирования установленные по умолчанию или изменить их.
Для изменения параметров форматирования, можно воспользоваться либо флагами и методами класса ios, либо манипуляторами ввода/вывода, представляющими собой функции, которые можно включать прямо в поток (файл ).
Флаги форматирования реализованы в виде отдельных фиксированных битов переменной (типа long) представления флагов. Поэтому несколько флагов с помощью логических битовых выражений можно объединять, тем самым по-разному комбинируя свойства потока. Список флагов форматирования представлен в таблице на слайдах 39-40.
Проверить значения любых флагов, установить или сбросить их позволяют методы класса ios, доступные через объекты cin и cout (слайд 41).
Примеры использования флагов и методов класса ios показаны на слайдах 42 и 43.
Наиболее простой способ изменения параметров и флагов форматирования обеспечивают специальные функции-манипуляторы, непосредственно воздействующие на потоковый вывод. Особенность манипуляторов и их отличие от обычных функций состоит в том, что их имена (без параметров) и вызовы (с параметрами) можно использовать в качестве правого операнда для операции обмена << или >>. В качестве левого операнда в этом выражении, как обычно, используется поток (объект, представляющий поток), и именно на этот поток оказывает влияние манипулятор.
Все изменения в потоке, внесенные манипулятором, сохраняются до следующей установки, за исключением setw(). См. слайды 45, 46, 47.
Слайд 25

Стандартные потоки. Манипуляторы с параметрами

Стандартные потоки. Манипуляторы с параметрами

Слайд 26

Стандартные потоки. Манипуляторы без параметров

Стандартные потоки. Манипуляторы без параметров

Слайд 27

Стандартные потоки. Пример использования манипуляторов #include #include using namespace std; int

Стандартные потоки. Пример использования манипуляторов
#include
#include
using namespace std;
int main()
{

double d[] = {1.234,-12.34567,123.456789,-1.234,0.00001};
cout << setfill('.') << setprecision(4)<< setiosflags(ios::showpoint|ios::fixed);
for(int i=0; i<5; i++)
cout << setw(12) << d[i] << endl;
return 0;
}