

1
Отличия С++: прототипы функций
Как было в С ?
#include <stdio.h> #include <conio.h>
void main()
{
print();
}
int print()
{
printf("Hi!"); return 1;
}
Как стало в С+
#include <iostream> using namespace std;
int print(); // Обязательно!!!
void main()
{
print();
}
int print()
{
cout<<"Hi!"; return 1;
}
В С++ описание прототипов функций стало обязательным.

2
Отличия С++: возврат из функции
Как было в С ?
Функция типа не void могла вернуть
неопределенное значение
int a() { return ” ”;
}
Как стало в С+
Для функции типа не void оператор return внутри этой функции должен
содержать значение указанного типа
#include "iostream"
using namespace std; int print();
void main()
{
print();
}
int print()
{
return "Hi!";
}

Отличия С++: объявление локальных |
3 |
|
Как было в С ? |
переменных |
|
Как стало в С+ |
|
#include <stdio.h> #include <conio.h>
void main()
{
int i,k=0;
for (i=0; i<10; i++) printf(”%u\n”,i);
k+=i;
}
#include <iostream> using namespace std;
void main()
{
int i;
for (i=0; i<10; i++) cout<<i<<endl;
int k=0; k+=i;
}
В С++ локальные переменные могут быть объявлены в любом месте программы, а не только в начале блока, как это было в языке С.

4
Отличия С++: консольный ввод/вывод
Как было в С ?
#include <stdio.h> #include <conio.h>
void main()
{
printf(”Example\n”);
getch();
}
Как стало в С+
#include <iostream> using namespace std;
void main()
{
char buf[10]; cout<<"Example"<< endl; cin>>buf;
}
В С++ консольный ввод вывод реализован также как и в С на основе стандартных потоков ввода/вывода
(stdin/stdout в С) cin и cout в С++ и при помощи перегруженных операторов поразрядного сдвига << и >>

5
Отличия С++: пример программы
Пример С++ программы
#include "iostream“ using namespace std; int input();
int print(); int array[10]; void main()
{
input(); print();
}
int input()
{
for (int i=0; i<10; cin>>array[i],i++); return 0;
}
int print()
{
for (int i=9; i>-1; cout<<array[i]<<" ",--i);
cout<<endl; return 0;
}
Программа вводит и выводит в обратном порядке массив из 10 целых чисел

6
Вспомнить все!
Унарные операции «*» и «++» или «--» имеют равный приоритет и при размещении рядом выполняются справа налево.
|
Ваша заготовка для |
|
экзамена… |
int x[4]= {0,2,4,6}, *p, n; |
|
p = &x[0]; |
// p равно адресу первого элемента массива x |
n = *p; |
// n равно 0, p равно &x[0] |
n = *p++; |
// n равно 0, p равно &x[1],т.к. x[1]=2 |
n = ++*p; |
// n равно 3, p равно &x[1],т.к. x[1]=2 |
n = *++p; |
// n равно 4, p равно &x[2],т.к. x[2]=4 |
n = (*p)++; |
// n равно 4, p равно &x[2], x[2]=5 |
n = ++(*p); |
// n равно 6, p равно &x[2], x[2]=6 |

7
Перегрузка функций
Один из видов полиморфизма, как базового принципа ООП.
Перегрузка функций ( function overloading) позволяет определять несколько функций с одним и тем же именем, если эти функции имеют различное количество и(или) типы аргументов.
Перегрузка функций обычно используется для создания функций, предназначенных для выполнения однотипных задач, оперирующих с различными структурами и типами
данных.
Нельзя перегрузить функции, отличающиеся друг от друга только типом возвращаемого значения.
При вызове перегруженной функции компилятор определяет адрес вызова нужной функции путем анализа количества, типа и порядка следования аргументов функции.
Каждая перегруженная функция имеет свой уникальный
идентификатор, называемый сигнатурой.

Перегрузка функций |
8 |
|
Примеры
#include "iostream“ |
Результат выполнения |
||
using namespace std; |
|||
программы: |
|||
void print(); |
|||
|
|||
void |
print(int n1); |
|
|
void |
print(int n1, int n2); |
|
void main()
{
print(); print(1); print(2,3);
}
void print() { cout << "Nothing " << endl; }
void print(int n1) { cout << "N1 = " << n1 << endl; }
void print(int n1, int n2) { cout << "N1 + N2 = " << n1+n2 << endl; }
Если в этот пример добавить функцию с прототипом, например, таким void print(int n1, int n2); ,то компилятор выработает синтаксическую ошибку, поскольку тело функции print(int , int ); уже определено.

Использование аргументов по умолчанию |
9 |
|
Данная особенность перегрузки функций позволяет определять аргументам значения по умолчанию, в случае, если аргумент не задан при вызове функции
Реализация такого механизма обеспечивается синтаксисом: возвращаемый_тип имя_функции (тип_аргумента=значение, …); int func (int a=0, int b=2, int c=7);
Данный синтаксис напоминает инициализацию переменных.
Пример
#include "iostream“
using namespace std; |
Результат выполнения |
void add(int a=0, int b=0, int c=0); |
программы: |
void main()
{
add(); add(1); add(2,3); add(2,3,4);
}
void add(int a, int b, int c) { cout << a+b+c << endl; }
Из примера видно, что нельзя задать значение по умолчанию аргументу a и присвоить какое-нибудь значение аргументу b.

10
Использование аргументов по умолчанию - 2
При описании функции аргументы по умолчанию задаются лишь один раз – или в описании прототипа функции, либо в определении функции. В последнем случае определение функции обязательно должно предшествовать ее вызову. Иначе компилятор выдает
сообщение об ошибке:
Пример
#include "iostream“ using namespace std; void add(int a, int b, int c);
void main()
{
add(); add(1); add(2,3); add(2,3,4);
}
void add(int a=0, int b=0, int c=0) { cout << a+b+c << endl; }
error C2660: 'add' : function does not take 0 arguments
error C2660: 'add' : function does not take 1 arguments
error C2660: 'add' : function does not take 2

11
Использование аргументов по умолчанию - 3
Если в определении функции хотя бы один аргумент описан как аргумент по умолчанию, то все аргументы, стоящие правее него в списке аргументов также должны быть заданы по умолчанию.
Если при вызове один аргумент был задан по умолчанию, то все последующие аргументы нельзя задать явно.
При использовании перегрузки функций и задании аргументов по умолчанию могут возникать ситуации неоднозначности, при которых компилятор не в состоянии выбрать требуемый вариант
Примерфункции. |
|
|
|
#include "iostream“ |
1>.\bsuir1.cpp(8) : error C2668: 'add' : ambiguous call to overloaded |
||
using namespace std; |
|||
function |
|||
void add(int c); |
1> |
.\bsuir1.cpp(4): could be 'void add(int,int)' |
|
void add(int a, int b=100); |
1> |
.\bsuir1.cpp(3): or 'void add(int)' |
|
1> |
while trying to match the argument list '(int)’ |
void main()
{
add(2,3); add(1);
}
void add(int a, int b) { cout << a+b << endl; }
void add(int c) { cout << c << endl; }

12
Пример
class Cl { int X;
public:
inline int Get () { return X; } inline void Set (int x=0) {X = x; }
};
…
Cl Obj;
Obj.Set (Obj.Get()+1);
inline функции не генерируются компилятором:
1)если в ней присутствуют
циклы, переключатели, переходы;
2)если она рекурсивна;
3)если в ней содержатся статические
переменные

Локальные и глобальные переменные |
13 |
|
Переменные можно объявлять в любом месте программы. При объявлении переменных им можно задавать конкретные инициализирующие значения. Такое свойство языка
программирования называется динамической инициализацией.
В программах могут возникать ситуации, когда имя глобальной переменной совпадает с именем локальной, объявленной внутри функции или блока. Для того, чтобы получить доступ из блока, где объявлена локальная переменная, к глобальной переменной с таким же именем, в С++ применяется оператор «области видимости»
(scopeПример resolution operator) – “::”.
#include "iostream“ using namespace std;
int i =0; // Глобальная переменная void func()
{
int i=1; // Локальная переменная ::i++;
i++;
cout << "G = " << ::i << endl; cout << "L = " << i << endl;
};
void main() { func(); }

Статические переменные |
14 |
|
Все локальные переменные являются переменными с локальным временем жизни: после выхода из блока, в котором они были описаны
– они исчезают.
Все локальные переменные по умолчанию имеют атрибут auto. Любую переменную или функцию можно задать с атрибутом static, который обеспечивает глобальное время жизни. Такие переменные называются статическими. Они начинают свое существование с самого начала работы программы. Если программист не
инициализировал явно статическую переменную, то компилятор сам |
|
присваивает ей значение 0. Локальные статические переменные |
|
имеют область видимости лишь в той функции или блоке, где |
|
объявлены, но при этом сохраняют свое значение на протяжении |
|
Пример |
Результат выполнения |
всего жизненного цикла программы |
|
#include "iostream“ |
|
using namespace std; |
программы: |
void func()
{
static int n=1;
cout << n++ << " start of function" << endl;
};
void main() { func(); func(); func(); }

15
Распределение динамической памяти в С++
Для управления динамической памятью в С++ используются операторы new и delete.
Динамическая память – поставляемый системой пул памяти для объектов, чей срок службы непосредственно управляется
программистом. |
new имя типа |
/ new |
Оператор new определяется как |
||
(имя типа) |
new имя типа |
|
но может иметь форму с инициализацией: |
|
Сначалаиници лизатор– распределяется объем, достаточный для того, чтобы содержать указанный тип данных. Затем базовый адрес объекта возвращается как
значение выражения new .
Если выделить память не удается – возвращается 0. Инициализатор – это обычно список параметров для конструктора создаваемого объекта.
Примеры:
Нельзя использовать его для инициализации массивов int *Num = new int;
double (*pVal) = new double;
char (*pArr)[10] = new char[sz][10]; // sz на 10 байт
int (**p) () = new (int (*[7]) ()); // массив из 7 указателей
// на функции, возвращающих целое значение

16
Освобождение динамической памяти в С++
Оператор delete определяется как |
delete выражение |
или |
delete [ ] выражение |
Выражение – это обычно переменная-указатель, которая была использована в операторе new.
Первая из форм используется для освобождения памяти, захваченной под отдельный объект, вторая – для освобождения памяти массивов.
Скобки указывают на то, что деструктор должен запрашиваться для каждого элемента освобождаемого массива.
Примеры:
int *Num = new int; delete Num;
double (*pVal) = new double; delete pVal;
char (*pArr)[10] = new char[sz][10]; // sz на 10 байт delete [] pArr;
int (**p) () = new (int (*[7]) ()); // массив из 7 указателей // на функции, возвращающих целое значение
delete [] p;

17
Передача аргументов в функцию
Вбольшинстве языков программирования аргументы в функциях передаются либо при помощи ссылки (by reference) либо по значению (by value) .
Впервом случае функция работает непосредственно с
переменной, а во втором – только с ее значением. Переменную, переданную по ссылке можно модифицировать, а переданную по значению – нет.
Встандартном С все аргументы передаются по значению,
идля того, чтобы модифицировать ее внутри функции, необходимо в качестве аргумента передать указатель на переменную.

18
Ссылки – передача аргументов
В языке С++ в отличие от С возмож- на передача параметров по ссылке. Ссылка (неявный указатель) – это по существу еще одно имя объекта.
3 варианта организации параметров:
по значению
int fun_a1(int a); // описание
fun_a1(i); |
// обращение |
int x = a; |
// использование |
по указателю
int fun_a2(int* a); // описание
fun_a2(&i); |
// обращение |
int x = *a; |
// использование |
по ссылке
int fun_a3(int& a); // описание
fun_a3(i); |
// обращение |
int x = a; |
// использование |

19
Ссылки
Функции могут в качестве возвращаемого значения использовать ссылку.
#include "iostream" |
Функция F() возвращает |
|
using namespace |
||
ссылку на переменную |
||
std; |
целого типа. |
|
int x; |
Необходимо отметить, что |
|
int &F() {return x;} |
оператор return в функции |
|
void main() |
F() возвращает не значение |
|
глобальной переменной x, а |
||
{ |
ссылку (адрес) этой |
|
F() = 0xff; |
переменной. |
|
} |
Дальнейшее действие |
|
|
компилятор воспринимает |
|
|
как занесение по адресу |
|
|
переменной x значения 0xff. |