Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
шпора к КПИЯП.docx
Скачиваний:
41
Добавлен:
25.02.2016
Размер:
135.65 Кб
Скачать

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

  Одним из подходов реализации принципа полиморфизма в языке С++ является использование перегрузки функций. В С++ две и более функций могут иметь одно и то же имя. Компилятор С++ оперирует не исходными именами функций, а их внутренними представлениями, которые существенно отличаются от используемых в программе. Эти имена содержат в себе скрытое описание типов аргументов. С этими же именами работают программы компоновщика и библиотекаря. По этой причине мы можем использовать функции с одинаковыми именами, только типы аргументов у них должны быть разными. Именно на этом и основана реализация одной из особенностей полиморфизма. Заметим, что компилятор не различает функции по типу возвращаемого значения. Поэтому для компилятора функции с различным списком аргументов – это разные функции, а с одинаковым списком аргументов, но с разными типами возвращаемого значения - одинаковые. Для корректной работы программ последнего следует избегать. Функции, имеющие одинаковые имена, но разные списки аргументов, называются перегруженными. Рассмотрим простой пример перегрузки функции sum, выполняющей сложение нескольких чисел различного типа.

Листинг 15.1 Перегрузка функции

#include "iostream.h" class cls  { int n; double f;  public:  cls(int N,float F) : n(N),f(F) {} int sum(int); // функция sum с целочисленнным аргументом double sum(double); // функция sum с дробным аргументом void see(); // вывод содержимого объекта }; int cls:: sum(int k)  { n+=k; return n; } double cls:: sum(double k)  { f+=k; return f; } void cls:: see() {cout <<n<<' '<<f<<endl;} void main() { cls obj(1,2.3); obj.see(); // вывод содержимого объекта cout <<obj.sum(1)<<endl; // вызов функции sum с целочисл. аргументом cout <<obj.sum(1.)<<endl; // вызов функции sum с дробным аргументом }

Результат:

1 2.3

2

3.3

 

В тоже время перегрузка функций может создавать проблему двусмысленности. Например:

 

class A

{ . . .

public:

void fun(int i,long j) {cout<<i+j<<endl;}

void fun(long i,int j) { cout<<i+j<<endl;}

};

 

main()

{ A a;

a.fun(2,2); // ошибка неизвестно какая из 2 функций вызывается

}

 

В этом случае возникает неоднозначность вызова функции fun объекта a.

 

2.7 Перегрузка операторов

  Как вы уже знаете, тип переменной определяет набор значений, которые она может хранить, а также набор операций, которые можно выполнять над этой переменной. Например, над значением переменной типа int ваша программа может выполнять сложение, вычитание, умножение и деление. С другой стороны, использование оператора плюс для сложения двух строк лишено всякого смысла. Когда вы определяете в своей программе класс, то по существу вы определяете новый тип. А если так, C++ позволяет вам определить операции, соответствующие этому новому типу.

Перегрузка оператора состоит в изменении смысла оператора (например, оператора плюс (+), который обычно в C++ используется для сложения) при использовании его с определенным классом. В данном уроке вы определите класс string и перегрузите операторы плюс и минус. Для объектов типа string оператор плюс будет добавлять указанные символы к текущему содержимому строки. Подобным образом оператор минус будет удалять каждое вхождение указанного символа из строки.

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

Ниже приведено определение класса, создающее класс string. Этот класс содержит один элемент данных, который представляет собой собственно символьную строку. Кроме того, этот класс содержит несколько различных методов и пока не определяет каких-либо операторов:

 

class string

{

public:

string(char *); // Конструктор

void str_append(char *);

void chr_minus(char);

void show_string(void);

private:

char data[256] ;

};

 

Как видите, класс определяет функцию str_append, которая добавляет указанные символы к содержимому строки класса. Аналогичным образом функция chr_minus - удаляет каждое вхождение указанного символа из строки класса. Следующая программа (Листинг 15.2) использует класс string для создания двух объектов символьных строк и манипулирования ими.

Листинг 15.2 STRCLASS.CPP

#include <iostream.h>  #include <string.h>  class string  {  public:  string(char *); // Конструктор  void str_append(char *);  void chr_minus(char);  void show_string(void);  private:  char data[256] ;  };  string::string(char *str)  {  strcpy(data, str);  }  void string::str_append(char *str)  {  strcat(data, str);  }  void string::chr_minus(char letter)  {  char temp[256] ;  int i, j;  for (i = 0, j = 0; data[i]; i++) // Эту букву необходимо удалить?  if (data[i] != letter) // Если нет, присвоить ее temp  temp[j++] = data[i];  temp[j] = NULL; // Конец temp  // Копировать содержимое temp обратно в data  strcpy(data, temp);  }  void string::show_string(void)  {  cout << data << endl;  } 

void main(void)  {  string title( "Учимся программировать на языке C++");  string lesson("Перегрузка операторов");  title.show_string() ;  title.str_append(" я учусь!");  itle.show_string();  lesson.show_string();  lesson.chr_minus('p') ;  lesson.show_string();  }

 

Как видите, программа использует функцию str_append для добавления символов к строковой переменной title. Программа также использует функцию chr_minus для удаления каждой буквы " р" из символьной строки lesson. В данном случае программа использует вызовы функции для выполнения этих операций. Однако, используя перегрузку операторов, программа может выполнять идентичные операции с помощью операторов плюс (+) и минус (-).

При перегрузке оператора используйте ключевое слово C++ operator вместе с прототипом и определением функции, чтобы сообщить компилятору C++, что класс будет использовать этот метод как оператор. Например, следующее определение класса использует ключевое слово operator, чтобы назначить операторы плюс и минус функциям str_append и chr_minus внутри класса string:

 

class string

{

public:

string(char *); // Конструктор

void operator +(char *);

void operator -(char); ————— Определение операторов класса void show_string(void);

private:

char data[256];

};

 

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

 

void string::operator +(char *str)

{

strcat(data, str);

}

 

Как видите, определение этой функции не содержит имени, поскольку здесь определяется перегруженный оператор класса. Для перегрузки оператора плюс программа не изменила обработку, которая осуществляется внутри функции (код этой функции идентичен коду предыдущей функции str_append). Вместо этого программа просто заменила имя функции ключевым словом operators соответствующим оператором. Следующая программа (Листинг 15.3) иллюстрирует использование перегружаемых операторов плюс и минус.

Листинг 15.3 OPOVERLD.CPP

#include <iostream.h>  #include <string.h>  class string  {  public:  string(char *); // Конструктор  void operator +(char *);  void operator -(char);  void show_string(void);  private;  char data[256] ;  };  string::string(char *str)  {  strcpy(data, str);  }  void string::operator +(char *str)  {  strcat(data, str);  }  void string::operator -(char letter)  {  char temp[256] ;  int i, j;  for (i = 0, j = 0; data[i]; i++) if (data[il 1= letter) temp[j++] = data[i];  temp[j] = NULL;  strcpy(data, temp);  }  void string::show_string(void)  {  cout << data << endl;  } 

void main(void)  {  string title( "Учимся программировать на C++");  string lesson("Перегрузка операторов");  title.show_string();  title + " я учусь!";  title.show_string() ;  lesson.show_string();  lesson - 'P';  lesson.show_string();  }

 

Как видите, программа использует перегруженные операторы:

 

title + " я учусь!"; // Добавить текст " я учусь!"

lesson - 'р'; // Удалить букву 'р'

 

В данном случае синтаксис оператора законен, но немного непривычен. Обычно вы используете оператор плюс в выражении, которое возвращает результат, например, как в операторе some_str = title + "текст ";. Когда вы определяете оператор, C++ предоставляет вам полную свободу в отношении поведения оператора. Однако, как вы помните, ваша цель при перегрузке операторов состоит в том, чтобы упростить понимание ваших программ. Поэтому следующая программа (Листинг 15.4) немного изменяет предыдущую программу, чтобы позволить ей выполнять операции над переменными типа string, используя синтаксис, который более согласуется со стандартными операторами присваивания.

Листинг 15.4 STR_OVER.CPP

#include <iostream.h>  #include <string.h>  class string  {  public:  string(char *); // Конструктор  char * operator +(char *) ;  char * operator -(char);  void show_string(void);  private:  char data[256] ;  } ;  string::string(char *str)  {  strcpy(data, str);  }  char * string::operator +(char *str)  {  return(strcat(data, str));  }  char * string::operator -(char letter)  {  char temp[256];  int i, j;  for (i = 0, j = 0; data[i]; i++) if (data[i] 1= letter) temp[j++] = data[i];  temp[j] = NULL;  return(strcpy(data, temp));  }  void string::show_string(void)  {  cout << data << endl;  }  void main(void)  {  string title("Учимся программировать на C++");  string lesson("Перегрузка операторов");  title.show_string();  title = title + " я учусь";  title.show_string() ;  lesson.show_string();  lesson = lesson - '?';  lesson.show_string();  }

 

Изменив перегруженные операторы плюс и минус таким образом, чтобы они возвращали указатель на символьную строку, программа может теперь использовать эти операторы в привычном для оператора присваивания виде:

 

title = title + " учимся программировать!";

lesson = lesson - 'р';