1.5. перегрузка функций и операций
В Си++ различные функции могут иметь одинаковое имя. Такие функции называются перегружаемыми. Цель перегрузки (присвоения одинаковых имен) функций состоит в том, чтобы функция выполнялась по-разному в зависимости от типа и количества ее аргументов. Например, функция вычисления модуля целого числа, числа с плавающей точкой и вектора будет выполняться по-разному:
#include <stdio.h> //библиотека стандартного ввода-вывода #include <math.h> //библиотека математических функций struct Vector3d { //структура трёхмерного вектора double x,y,z; //состоит из трёх координат в пространстве };
double absl(double x) //эта функция возвращает модуль double { if(x<0) return -x;//воспользуемся определением модуля else return x; }
double absl(Vector3d v) //эта функция возвращает модуль(длину) //трёхмерного вектора { return sqrt(v.x*v.x+v.y*v.y+v.z*v.z); //корень квадратный из //суммы квадратов координат } int absl(int i) //эта функция возвращает модуль целого числа { if(i<0) return -i;//воспользуемся определением модуля return i; }
main() { Vector3d n={3.14159, 2.71828, -1}; //n-трёхмерный вектор printf(" Входные данные: "); printf("Трёхмерный вектор n={\%f,\%f,\%f} ",n.x,n.y,n.z); printf(" Выходные данные:"); printf(" Модуль вектора n равен \%f",absl(n)); //найдём модуль n printf(" Модуль целого числа -1 равен \%d",absl(-1)); //вызов функции для int printf(" Модуль double числа -1 равен \%f",absl(-1.)); //вызов функции для double }
Результаты работы программы
Входные данные: Трёхмерный вектор n={3.141590,2.718280,-1.000000} Выходные данные: Модуль вектора n равен 4.273012 Модуль целого числа -1 равен 1 Модуль double числа -1 равен 1.000000
Аналогичным образом перегружаются операции. Перегрузка операций осуществляется для типов данных, определяемых структурами. Операция перегружается как функция, имя которой состоит из слова operator с добавленным справа символом операции. Например, подпрограмму конкатенации строк, определяемых структурой
Struct String{ int length; //длина строки char *p; //указатель на строку }
можно определить как операцию сложения строк
String operator+(String s,String t);
Приведём пример программы, в которой определена такая операция:
#include <stdio.h> //библиотека стандартного ввода-вывода #include <string.h> //библиотека функций для работы со строками #include <conio.h> //библиотека консольного ввода-вывода struct string { //структура string int length; //содержит длину char *p; //и саму строку }; string operator+(string s, string t) //перегрузка операции + { int i; string res; //результирующая строка res.p=new char[s.length+t.length+1];//выделим память для строки strcpy(res.p, s.p); //копируем первую строку strcpy(res.p+s.length, t.p); //копируем вторую строку res.length=s.length+t.length; //заполняем поле структуры- //длина строки return res; }
void main() { string s1={3,"abc"}, s2={4,"1234"},s3; //строки s1,s2,s3 clrscr(); printf("Входные данные: "); printf(" Первая строка \%s ",s1.p); printf("Длина первой строки \%d ",s1.length); printf("Вторая строка \%s ",s2.p); printf("Длина второй строки \%d ",s2.length); s3=s1+s2; //используем перегруженную //операцию + printf(" Выходные данные: "); printf("Результат конкатенации первой и второй строк \%s ",s3.p); printf("Длина результирующей строки \%d ",s3.length); //результат конкатенации s1 //s2 - "abc1234" длина - 7 }
Результаты работы программы
Входные данные: Первая строка abc Длина первой строки 3 Вторая строка 1234 Длина второй строки 4
Выходные данные: Результат конкатенации первой и второй строк abc1234 Длина результирующей строки 7
Те же самые результаты могут быть получены при запуске следующей программы, отличающейся от приведённой выше способом копирования входных строк в результирующую:
#include <stdio.h> //библиотека стандартного ввода-вывода #include <string.h> //библиотека функций для работы со строками #include <conio.h> //библиотека консольного ввода-вывода struct string { //структура string int length; //содержит длину char *p; //и саму строку }; string operator+(string s, string t) //перегрузка операции + { int i; string res; //результирующая строка res.p=new char[s.length+t.length+1];//выделим память для строки for (i=0; i<s.length; i++) res.p[i]=s.p[i]; //копируем первую строку for (i=s.length; i<s.length+t.length; i++) res.p[i]=t.p[i-s.length]; //копируем вторую строку res.p[i]=0; //строка завершается 0 res.length=s.length+t.length; //заполняем поле структуры- //длина строки return res; }
void main() { string s1={3,"abc"}, s2={4,"1234"},s3; //строки s1,s2,s3 clrscr(); printf("Входные данные:",s3.p); printf(" Первая строка \%s ",s1.p); printf("Длина первой строки \%d ",s1.length); printf("Вторая строка \%s ",s2.p); printf("Длина второй строки \%d ",s2.length); s3=s1+s2; //используем перегруженную операцию + printf(" Выходные данные: "); printf("Результат конкатенации первой и второй строк \%s ",s3.p); printf("Длина результирующей строки \%d ",s3.length); //результат конкатенации s1 //s2 - "abc1234" длина - 7 }
Отметим, что невозможно определить эту операцию с помощью char* operator+(char* s, char* t) , поэтому приходится объявлять структуру, содержащую строку.
Правила составления перегружаемых функций и операций: для перегружаемых операций (над структурами) отсутствует возможность передачи параметров по умолчанию; перегрузка функций не должна приводить к конфликту с параметрами, заданными по умолчанию. Например, нельзя определить две функции: int f(int x=0); int f(); ибо неясно, к вызову какой из этих функций приводит оператор y=f(); перегружаемые функции и операции не могут различаться только по типу возвращаемого значения, например, объявление функций: Void f(int); int f(int); является ошибочным.
Пример. Рассмотрим структуру, реализующую двумерный вектор. Определим для него операции суммы, разности, унарного минуса, скалярного произведения.
#include <stdio.h> //библиотека стандартного ввода-вывода
struct Vector { //структура вектора на плоскости double x,y; //состоит из координат х и у };
Vector operator+(Vector v, Vector w) //перегрузим операцию сложения { Vector t; t.x=v.x+w.x; t.y=v.y+w.y; //складываются соответствующие координаты //двух векторов return t; }
Vector operator-(Vector v, Vector w) //перегрузим операцию вычитания { Vector t; t.x=v.x-w.x; t.y=v.y-w.y; //находится разность соответствующих //координат двух векторов return t; }
Vector operator-(Vector v) //перегрузим операцию унарного минуса { Vector t; t.x=-v.x; t.y=-v.y; //найдём вектор,противоположно направленный //и имеющий ту же длину, для данного return t; } double operator*(Vector v, Vector w) //перегрузим операцию умножения { return v.x*w.x+v.y*w.y;//найдём скалярное произведение двух векторов }
int main() { Vector a={1,0}, b={-1,1},c,d,e; printf (" Входные данные: "); printf ("Вектор а={\%f,\%f},b={\%f,\%f} ",a.x,a.y,b.x,b.y); c=a-b; printf(" Результат вычитания a-b={\%f,\%f}",c.x,c.y); //вычитание printf(" Результат скалярного произведения a*b=\%f",a*b); //произведение d=a+b; printf(" Результат сложения a+b={\%f,\%f}",d.x,d.y); //сложение e=-a ; printf(" Вектор противоположный а это вектор е={\%f,\%f}",e.x,e.y); //унарный минус }
Результаты работы программы
Входные данные: Вектор а={1.000000,0.000000},b={-1.000000,1.000000}
Выходные данные: Результат вычитания a-b={2.000000,-1.000000} Результат скалярного произведения a*b=-1.000000 Результат сложения a+b={0.000000,1.000000} Вектор противоположный а это вектор е={-1.000000,-0.000000}
|
| Оглавление| |