Скачиваний:
51
Добавлен:
15.06.2014
Размер:
470.02 Кб
Скачать

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; }

Встраиваемые функции в языке С++ задаются с помощью спецификатора inline.
Механизм использования таких функций похож на использование макроопределений с параметрами в языке С.
Если функция имеет спецификатор inline, то ее тело встраивается в блок программы после места ее вызова. Преимуществом таких функций является быстродействие, заключающееся в экономии времени процессора на вызов функции и обеспечения механизма
возврата из нее. В MSDN такие действия определены как
Function calls (including parameter passing and placing the object's address on the stack)
Preservation of caller's stack frame New stack-frame setup Return-value communication
Old stack-frame restore Return
Встраиваемые функции

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.