Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

OOP / Лекция 4

.pdf
Скачиваний:
33
Добавлен:
20.04.2015
Размер:
96.28 Кб
Скачать

// m1=m2+m3; ошибка!!! использование операндов производных типов для операции сложения запрещено

И всё же возможность сохранения привычной структуры выражений для производных типов в C++ существует. Для этого в программе необходимо перегрузить операцию для нестандартного типа данных. Перегрузка операции заключается в определении специальной функции, которая будет вызываться при использовании операции языка С++ с нестандартными типами данных. Функция, перегружающая операцию в С++ называется «операция-функция» и должна выглядеть следующим образом:

тип operator знак_операции (список формальных_параметров) {тело_функции }

Здесь тип – тип возвращаемого функцией значения, operatorключевое слово, определяющее, что данная функция перегружает операцию, знак_операции – знак той операции языка С++, которую перегружает данная функция. Количество параметров функции определяется количеством операндов у соответствующей операции, а также способом определения функции. Операция-функция может быть как компонентной функцией некоторого класса, так и внешней функцией. Рассмотрим пример перегрузки операций для класса array2 (двумерный массив целых чисел).

//Листинг 18. Перегрузка операций для класса «двумерный массив целых чисел» #include <iostream.h>

#include <conio.h> class array2

{ int **mas; //указатель на массив

int n,m;

//количество строк и столбцов

public:

 

array2(int,int); //конструктор

void ReadMas(); //ввод массива с клавиатуры

void WriteMas(); //вывод элементов массива на экран

~array2();

//деструктор

operator int();

//перегрузка операции приведения типа

friend array2& operator*(array2&,array2&); //дружественная функция

перегрузки / /операции умножения

void operator=(array2&); //перегрузка операции присвоения

};

 

array2::array2(int a,int b){n=a;m=b;

//динамически выделяем память под

двумерный массив

 

mas=new int *[n];

 

for (int i=0;i<n;i++)

 

mas[i]=new int[m];

 

}

 

void array2::ReadMas(){

 

cout<<"Введите массив \n"; for (int i=0;i<n;i++)

for (int j=0;j<m;j++) cin>>mas[i][j];}

41

void array2::WriteMas() { for (int i=0;i<n;i++)

{ for (int j=0;j<m;j++) cout<<mas[i][j]<<'\t'; cout<<'\n';

}}

array2::~array2(){for (int i=0;i<n;i++) delete [] mas[i];

delete[]mas;

}

array2& operator*(array2& m1,array2& m2) //внешняя функция перегрузки операции

//умножения

{ if(m1.m==m2.n) {array2 *pta; int s;

pta=new array2(m1.n,m2.m); for(int i=0;i<m1.n;i++)

{ for(int j=0;j<m2.m;j++) {s=0;

for(int k=0;k<m1.m;k++) s+=m1.mas[i][k]*m2.mas[k][j];

pta->mas[i][j]=s;

}

}

return *pta;

}

else cout<<"Error";

}

array2::operator int() { int sum=0;

for(int i=0;i<n;i++) for(int j=0;j<m;j++) sum+=mas[i][j]; return sum;

}

void array2::operator=(array2& m2)

{if(n==m2.n&&m==m2.m) for(int i=0;i<n;i++) for(int j=0;j<m;j++) mas[i][j]=m2.mas[i][j]; else cout<<"Error";

}

main()

{ array2 m(2,3),m1(3,4),m2(2,4); m.ReadMas();

m1.ReadMas();

m2=m*m1; //перемножаем массивы по правилу перемножения матриц m2.WriteMas();

int c=int(m2); //получаем сумму элементов массива cout<<c;

getch();

}

В приведенном примере для класса «двумерный массив целых чисел» перегружены три операции: операция умножения ‘*’, выполняющая умножение массива по правилам перемножения матриц, операция приведения типа ‘int()’, которая применительно к массиву вычисляет сумму элементов массива, а также операция присвоения ‘=’, которая поэлементно копирует содержимое одного массива в другой. Рассмотрим подробнее операцию-функцию operator * . Данная операция-функция определена как внешняя по отношению к классу функция с правами друга, так как она работает с частными компонентами класса n, m, mas. Функция имеет два параметра – это операнды операции умножения. После такого объявления функции любое использование в программе выражения типа a*b при условии, что а и b являются объектами класса array2, приводит к вызову operator *(a,b). Подобный вызов операции-функции можно непосредственно поместить в текст программы, но он уступает в понятности и наглядности использованию обычной операции умножения. Таким образом, при определении операции-функции как внешней функции количество ее параметров должно совпадать с арностью перегружаемой операции, поскольку операнды перегруженной операции становятся фактическими параметрами соответствующей операции-функции. Для перегрузки операции приведения типа ‘int()’ определена операция-функция как метод класса array2. При подобном определении один из операндов операции становится тем объектом, для которого вызывается операция-функция, а остальные операнды (если они есть) передаются как фактические параметры. Таким образом, для вызова операции приведения типа с параметром – объектом класса array2 в последнем примере: int(m2) будет вызвана операция-функция в следующем варианте:

m2.operator int()

Если бы операция умножения была перегружена методом класса array2 , а не внешней функцией, то для нее необходимо было бы определить лишь один формальный параметр – через него в функцию передавался бы лишь второй операнд операции умножения. Первый операнд в этом случае становится тем объектом, для которого вызывается операция функция:

//Листинг 19. Определение операции-функции как метода класса

class array2

 

{ …

 

array2& operator*(array2& m2)

//функция перегрузки операции

//умножения как метод класса

 

{ if(m==m2.n)

 

{array2 *pta;

 

int s;

 

pta=new array2(n,m2.m);

 

for(int i=0;i<n;i++)

 

{ for(int j=0;j<m2.m;j++)

 

{s=0;

for(int k=0;k<m;k++) s+=mas[i][k]*m2.mas[k][j]; pta->mas[i][j]=s;

}

}

return *pta;

}

else cout<<"Error

}

};

main()

{ array2 m(2,3),m1(3,4),m2(2,4);

m2=m*m1;//можно записать в виде m2=m.operator *(m1)

}

Перегрузка операции присваивания необходима для класса array2 в связи с тем, что обычное копирование компонентных данных из одного объекта в другой, которое производит операция присваивания по умолчанию, не подходит для поставленной задачи. Если написать выражение m1=m2, не переопределяя операцию присваивания, то компонент mas одного объекта будет скопирован в компонент mas другого, что приведет к использованию обоими объектами одного и того же динамического массива в дальнейшем. Переопределив же операцию присваивания, мы при присваивании объектов копируем элементы одного динамического массива в другой.

При перегрузке операций существует ряд ограничений: нельзя перегружать некоторые операции (‘.’, ’?:’, ’::’, ‘sizeof’, ‘##’, ‘#’, ‘.*’), нельзя вводить новые знаки операций, нельзя изменять приоритеты операций, для некоторых операций (‘=’,’[]’,’->’) операцию-функцию можно определять только как нестатическую компонентную функцию класса.

Соседние файлы в папке OOP