Плюсы использования функций




Прототип функции

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

double line(double x1,double y1,double x2,double y2);

double square(double a, double b, double c);

bool triangle(double a, double b, double c);

double line(double,double,double,double);

double square(double, double, double);

bool triangle(double, double, double);

Это прототипы функций, описанных выше.

При наличии прототипов вызываемые функции не обязаны размещаться в одном файле с вызывающей функцией, а могут оформляться в виде отдельных модулей и храниться в откомпилированном виде в библиотеке объектных модулей. Это относится и к функциям из стандартных модулей. В этом случае определения библиотечных функций уже оттранслированные и оформленные в виде объектных модулей, находятся в библиотеке компилятора, а описания функций необходимо включать в программу дополнительно. Это делают с помощью препроцессорных команд include< имя файла>.

Имя_файла – определяет заголовочный файл, содержащий прототипы группы стандартных для данного компилятора функций. Например, почти во всех программах мы использовали команду #include <iostream.h> для описания объектов потокового ввода-вывода и соответствующие им операции.

При разработке своих программ, состоящих из большого количества функций, и, размещенных в разных модулях, прототипы функций и описания внешних объектов (констант, переменных, массивов) помещают в отдельный файл, который включают в начало каждого из модулей программы с помощью директивы include”имя_файла”.

Параметры функции

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

При передаче по значению выполняются следующие действия:

- вычисляются значения выражений, стоящие на месте фактических параметров;

- в стеке выделяется память под формальные параметры функции;

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

Пример:

double square(double a, double b, double c)

{

//функция возвращает площадь треугольника, заданного длинами сторон а,b,c

double s, p=(a+b+c)/2;

return s=sqrt(p*(p-a)*(p-b)*(p-c));//формула Герона

}

1) double s1=square(2.5,2,1);

2) double a=2.5,b=2,c=1;

double s2=square(a,b,c);

3) double x1=1,y1=1,x2=3,y2=2,x3=3,y3=1;

double s3=square(sqrt(pow(x1-x2,2)+pow(y1-y2,2)),//расстояние между 1и2

sqrt(pow(x1-x3,2)+pow(y1-y3,2)), //расстояние между 1 и 3

sqrt(pow(x3-x2,2)+pow(y3-y2,2)));//расстояние между 2 и3

Локальные и глобальные переменные

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

int*f()

{

int a;

....

return&a;// НЕВЕРНО

}

Глобальные переменные – это переменные, описанные вне функций. Они видны во всех функциях, где нет локальных переменных с такими именами.

Пример:

int a,b;//глобальные переменные

void change()

{

int r;//локальная переменная

r=a;a=b;b=r;

}

void main()

{

cin>>a,b;

change();

cout<<”a=”<<a<<”b=”<<b;

}

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

Перегрузка функций

В С++ вы можете создавать функции с одинаковыми именами. Вы наверно удивлены, что такое вообще возможно так, как если у нас будет 3 функции с одинаковыми именами и мы захотим вызвать одну из этих функций, то мы таким образом вызовем все 3 функции и получится полная каша. Но компилятор думает про это совершенно по-другому.

Все дело в том, что у каждой функции есть свое полное имя(или по-другому сигнатура). Параметры функции — это вся информация о функции. В эту информацию входят:

· Имя функции.

· Число аргументов функции.

· Типы аргументов.

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

Перегрузка функций — это создание функций с одинаковыми именами, но с разными сигнатурами (полными именами).

В примере ниже все функции разные, хотя и имена у них одинаковые:

  int func(int a) { // выполнение функции номер 1 } double func() { // выполнение функции номер 2 } int func(double b, double h) { // выполнение функции номер 3 } long long func(int n, int c, int g) { // выполнение функции номер 4 }

Распространенной ошибкой является мнение, что тип возвращаемого значения функции входит в полное имя функции.

В примере ниже три функции имеют одинаковые типы возвращаемого значения (но полные имена у них совершенно идентичны), и поэтому компилятор начнет ругаться на нас (почему мы создали одинаковые функции!).

  int func() {   } double func() { //ошибка: функция с таким именем уже существует } long long func() { //ошибка: функция с таким именем уже существует }

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

В C++ вы не можете вызвать функцию до объявления самой функции. Все потому, что компилятор не будет знать полное имя функции (имя функции, число аргументов, типы аргументов). Таким образом в примере ниже компилятор сообщит нам об ошибке:

  int main() { Sum_numbers(1, 2);   return 0; }   int Sum_numbers(int a, int b) { cout << a + b; }

Так, при вызове функции Sum_numbers() внутри функции main() компилятор не знает ее полное имя.

Конечно компилятор C++ мог просмотреть весь код и определить полное имя функции, но этого он делать не умеет и нам приходится с этим считаться.

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

Прототип функции — это функция, в которой отсутствует блок кода (тело функции). В прототипе функции находятся:

· Полное имя функции.

· Тип возвращаемого значения функции.

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

  int Sum_numbers(int a, int b); // прототип функции   int main() { Sum_numbers(1, 2);   return 0; }   int Sum_numbers(int a, int b) { // сама функция cout << a + b; }

Так, с помощью прототипа мы объясняем компилятору, что полным именем функции является Sum_numbers(int a, int b), и кроме этого мы говорим компилятору о типе возвращаемого значения, у нас им является тип int.

Плюсы использования функций

Давайте попробуем сформулировать плюсы использования функций у себя в программе:

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

· Большое уменьшение количества написания кода.

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


 

 

Виртуальные функции — специальный вид функций-членов класса. Виртуальная функция отличается об обычной функции тем, что для обычной функции связывание вызова функции с ее определением осуществляется на этапе компиляции. Для виртуальных функций это происходит во время выполнения программы.

Для объявления виртуальной функции используется ключевое слово virtual. Функция-член класса может быть объявлена как виртуальная, если

· класс, содержащий виртуальную функцию, базовый в иерархии порождения;

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

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

Определение того, какой экземпляр виртуальной функции вызывается по выражению вызова функции, зависит от класса объекта, адресуемого указателем или ссылкой, и осуществляется во время выполнения программы. Этот механизм называется динамическим (поздним) связыванием или разрешением типов во время выполнения.

Указатель на базовый класс может указывать либо на объект базового класса, либо на объект порожденного класса. Выбор функции-члена зависит от того, на объект какого класса при выполнении программы указывает указатель, но не от типа указателя. При отсутствии члена порожденного класса по умолчанию используется виртуальная функция базового класса.

#include <iostream>
using namespace std;class X {

protected:

int i;public:

void seti(int c)

{i = c;}

virtual void print()

{cout << endl <<"class X: " << i;}

};

class Y: public X {

public:

void print() {cout << endl << "class Y: " << i;}

};
int main() {

X x;

X *px=&x; // Указатель на базовый класс

Y y;

x.seti(10);

y.seti(15);

px->print(); // класс X: 10

px=&y;

px->print(); // класс Y: 15

cin.get();

return 0;
}

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

В терминологии ООП «объект посылает сообщение print и выбирает свою собственную версию соответствующего метода». Виртуальной может быть только нестатическая функция-член класса. Для порожденного класса функция автоматически становится виртуальной, поэтому ключевое слово virtualможно опустить.

// Выбор виртуальной функции

#include <iostream>
using namespace std;

class figure {

protected:

double x, y;

public:

figure(double a=0, double b=0) {x = a; y = b;}

virtual double area() {return(0);} // по умолчанию
};
class rectangle: public figure {

public:

rectangle(double a=0, double b=0): figure(a, b) {};

double area() {return(x*y);}

};
class circle: public figure {

public:

circle(double a=0): figure(a, 0) {};

double area() {return(3.1415*x*x);}

};
int main() {

figure *f[2];

rectangle rect(3, 4);

circle cir(2);

double total = 0;

f[0] = &rect;

f[1] = &cir;

total = f[1]->area();

cout << total << endl;

total += f[0]->area();

cout << total << endl;

cin.get();

return 0;
}

 



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2021-04-06 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: