Перегрузка операций в С++

Понятие перегрузки (доопределения) операций и её разновидности. Пример соответствующей программы перегрузки, понятие полиморфизма и правила isA. Использование классов операторов в программах языка С++, конструкций операторов и производных классов.

Рубрика Программирование, компьютеры и кибернетика
Вид реферат
Язык русский
Дата добавления 30.10.2011
Размер файла 19,9 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

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

Размещено на http://www.allbest.ru/

Размещено на http://www.allbest.ru/

Содержание

Введение

1. Понятие перегрузки операций

2. Перегрузка различных операций

3. Пpимеp программы с перегрузкой операций

4. Полиморфизм

5. Правило isA( )

Заключение

Список литературы

Введение

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

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

Перегрузка операторов может упростить наиболее общие операции класса и улучшить читаемость программы.

перегрузка доопределение оператор полиморфизм

1. Понятие перегрузки операций

В С++ используется множество операций, среди которых арифметические операции ( +, *, -, / и т.п. ), логические ( >>, &, | и т.п. ), операции отношений ( ==, >, <, <= и т.п. ).

На все операции языка С++, кроме операций объявления, new, delete, и других операций, связанных с определением производных типов данных, распространяется свойство перегружаемости, т.е. возможности использования в различных случаях для одной и той же операции операндов различных типов. Так, например, операция сложения позволяет "смешивать" типы int, double, float и другие в одном выражении. Такой полиморфизм обеспечен внутренними механизмами языка С++.

В том случае, если программист определил какие-либо свои классы, он может сам решить, что будут означать операции языка С++, когда они используются над объектами этих классов, тем самым расширив число типов данных, для которых можно использовать ту или иную операцию. Переопределять или доопределять операции допускается не только для знаков операций, введенных самим программистом, но и для знаков, определенных в языке изначально (таких, как “+” или “*”).

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

Например, можно доопределить операцию "+" для текстовых строк как операцию конкатенации (слияния строк) следующим образом.

class String {

protected:

char *PointerToString; // Указатель на строку

int StringSize; // Длина строки

public:

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

~String ( ); // Деструктор

void Print( );

String operator+ ( String ); // Перегрузка операции

}; // "+"

//----------------------------------------------------//

// Определение смысла операции "+" как //

// конкатенации текстовых строк //

//----------------------------------------------------//

String String::operator+ ( String One )

{

// Инициализация объекта Result

// (он будет результатом конкатенации)

String Result(" ");

int Length;

// Копирование первой строки в результурующую

strcpy(Result.PointerToString, One.PointerToString);

// Установка длины строки объекта, для которого

// будет вызвана операция

Length = strlen( One.PointerToString );

// Добавление второй строки вслед за первой

memcpy(Result.PointerToString,PointerToString+Length,

strlen( PointerToString ) );

// Установка общей длины строки в результате

Result.StringSize = strlen( Result.PointerToString ) + 1;

Result.PointerToString[Result.StringSize] = '\0';

return (Result);

}

2. Перегрузка различных операций

Для многих операций С++ существуют свои особенности при перегрузке (доопределении). Так унарные операции переопределяются с описанием функции операции без аргумента, например:

class A { //...

A operator- - ( ) { // текст функции для операции “- -“ };

//...

};

Соответственно доопределение бинарной операции использует описание функции операции с одним аргументом, т.к. вторым является объект, для которого вызвана операция. Следует также помнить, что операция присваивания "=" может перегружаться только объявлением метода без описателя static. То же относится к операциям "( )" и "[ ]".

3. Пpимеp программы с перегрузкой операций

Пусть необходимо запрограммировать переопределение операций для объекта "строка", где операция "+" будет означать конкатенацию строк.

/********************/

/* Operations for */

/* Class */

/* String */

/********************/

/* v.25.12.2002 */

#include "iostream.h"

#include "string.h"

class String {

protected:

char *PointerToString; // Указатель на строку

int StringSize; // Длина строки

public:

String ( char * );

~String ( );

void Print( );

String operator+ ( String );

};

// Конструктор

String::String ( char * Str )

{

StringSize = strlen(Str);

PointerToString = new char [StringSize + 1];

strcpy ( PointerToString, Str);

}

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

String::~String ( )

{

StringSize = 0;

delete PointerToString;

PointerToString = NULL;

}

// Переопределение операции

String String::operator+ ( String One )

{

String Result(" ");

int Length;

strcpy(Result.PointerToString, One.PointerToString);

Length = strlen( One.PointerToString );

memcpy(Result.PointerToString,PointerToString+Length,

strlen( PointerToString ) );

Result.StringSize = strlen( Result.PointerToString ) + 1;

Result.PointerToString[Result.StringSize] = '\0';

return (Result);

}

// Определение функции вывода объекта

void String::Print( )

{

cout << PointerToString;

}

// Программа, проверяющая работоспособность операции "+"

void main( )

{

String A("111");

A.Print( );

String B("222");

B.Print( );

String C(" ");

C = A + B;

C.Print( );

}

4. Полиморфизм

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

Однако и подкласс (производный класс) может содержать функцию-метод с именем, совпадающим с уже присутствующим в базовом классе. Такой случай назвают полиморфизмом. Например, конструкции типа SubClass из нижеследующего фрагмента программы могут иметь собственные методы для печати print( ).

struct SubClass : public Base {

SubClass(char* n) : Base(n) { }

void print( ) {

cout<< "Это компонент подкласса="

<< name

<< endl;

}

};

void main( ) {

Base aBaseObject;

SubClass aSubClassObject;

}

Ссылка на print( ) по умолчанию относится к методу самого низкого уровня, который применим в этом случае. В приведенном примере aBaseObject.print( ) ссылается на Base::print( ), тогда как aSubClassObject.print( ) ссылается на SubClass::print( ). Программа может вызывать конкретную функцию, если задано полностью квалифицированное имя, например aSubClassObject.Base::print( ). Методы подкласса могут таким же способом ссылаться на методы базового класса. Вместе с тем программа не может ссылаться на aBaseObject.SubClass:: print( ), поскольку SubClass::print( ) не является компонентом класса Base.

Если метод подкласса перекрывает своим новым определением метод базового класса, то могут возникнть проблемы. Рассмотрим, что будет означать для функции fn( ) определение нового метода print( ).

void fn(Base& aBaseRef) {

cout<<"Из fn( ):";

aBaseRef.print( );

}

Объект aBaseRef теперь объявлен как относящийся к классу Base. Ссылка на aBaseRef.print() всегда будет фактически относиться к Base::print(), но вместо объекта базового класса будет использован объект подкласса. Таким образом, fn() можно вызывать либо как fn(aSub ClassObject), либо как fn(aBaseClassObject). Вызов print() соответственно, приведет к вызову функции SubClass:: print().

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

C++ оставляет использование позднего связывания на усмотрение программиста. По умолчанию, даже при наличии неоднозначности имен, транслятором принимается решение о раннем связывании имен программы. Следовательно, по способу записи определений классов fn( ) всегда будет давать обращение к Base::print( ). Позднее связывание здесь не выполняется. Добавление в определение функции ключевого слова virtual делает эту функцию полиморфной.

virtual void print( ) {

cout << "Это компонент базового класса="

<< name

<< endl;

}

Вызовы virtual print( ) используют позднее связывание.

Виртуальная функция не может быть объявлена как static (статическая). При отсутствии объекта Turbo C++ не может выполнить позднее связывание.

Объявление виртуальной функции-метода автоматически делает виртуальными все функции с этим именем в подклассах.

Если метод в подклассе с тем же именем принимает другие аргументы, то никакого полиморфизма нет. Рассмотрим пример:

#include <iostream.h>

struct Base {

virtual void print( ) {

cout << "Это объект базового класса"

<< endl;

}

};

struct SubClass : public Base {

virtual void print(char* c) {

cout << "Это объект подкласса "

<< c

<< endl;

}

};

void fn(Base& obj) {

obj.print( );

obj.print("Relative object"); //ошибка компилятора #1

}

void main( ) {

SubClass aSubClass;

aSubClass.print( ); //ошибка компилятора #2

aSubClass.print("aSubClass");

fn(aSubClass);

}

Оба класса, Base и SubClass, содержат функции print( ); однако, эти две функции имеют разные аргументы. Компилятор C++ не позволит сделать вызов Base::print( ) с неверными типами аргументов, что приведет к ошибке, с соответствующим сообщением от компилятора. Аналогичная ситуация возникнет и во втором случае, когда компилятор встретит вызов SubClass:: print( ).

5. Правило isA( )

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

Для решения этой проблемы программист должен определить метод идентификации, обычно называемый isA( ). Это виртуальное правило возвращает константу, которая является уникальной для каждого типа подкласса. Можно перевести слово isA как “являющийся (под)классом определенного типа”. Рассмотрим следующую некомпонентную версию функции print( ).

#include <iostream.h>

struct Base {

enum ClassType {BASE, SUBCLASS};

virtual ClassType isA( ) {return BASE;}

}

void print(Base& obj) {

if (obj.isA( )==Base::BASE)

cout<< "Это объект базового класса\n";

else

if (obj.isA( )==Base::SUBCLASS)

cout<< "Это объект подкласса\n";

else

cout<< "Это неизвестный тип объекта\n";

}

void fn(Base& obj) {

print(obj) ;

}

void main( ) {

Base aBaseClass;

SubClass aSubClass;

fn(aBaseClass);

fn(aSubClass);

}

На выходе этой программы будет следующее:

Это объект базового класса

Это объект подкласса

Заключение

Перегрузка операторов -- это возможность назначать новый смысл операторам при использовании их с определенным классом. Используя перегрузку операторов, вы можете повысить удобочитаемость ваших программ и облегчить их понимание, выражая операции класса более понятным образом. Нам известно, как разделить данные между объектами с помощью элемента static и как использовать методы класса, когда никакие объекты класса не объявляются. В качестве выводов можно сказать следующее:

Чтобы перегрузить оператор, вы должны определить класс, которому оператор будет назначен.

Когда вы перегружаете оператор, перегрузка действует только для класса, в котором он определяется. Если программа использует оператор с неклассовыми переменными (например, переменными типа int или float), используется стандартное определение оператора.

Чтобы перегрузить оператор класса, используйте ключевое слово C++ operator для определения метода класса, который C++ вызывает каждый раз, когда переменная класса использует оператор.

C++ не позволяет вашим программам перегружать оператор выбора элемента (.), оператор указателя на элемент (.*), оператор разрешения области видимости (::) и условный оператор сравнения (?:).

Список литературы

1. М. Эллис, Б. Строуструп. Справочное руководство по языку C++ с комментариями: Пер. с англ. - Москва: Мир, 1992. 445с.

2. Стенли Б. Липпман. C++ для начинающих: Пер. с англ. 2тт. - Москва: Унитех; Рязань: Гэлион, 1992, 304-345сс.

3. Бруно Бабэ. Просто и ясно о Borland C++: Пер. с англ. - Москва: БИНОМ, 1994. 400с.

4. В.В. Подбельский. Язык C++: Учебное пособие. - Москва: Финансы и статистика, 1995. 560с.

5. Ирэ Пол. Объектно-ориентированное программирование с использованием C++: Пер. с англ. - Киев: НИИПФ ДиаСофт Лтд, 1995. 480с.

6. Т. Фейсон. Объектно-ориентированное программирование на Borland C++ 4.5: Пер. с англ. - Киев: Диалектика, 1996. 544с.

Размещено на Allbest.ru


Подобные документы

  • Представление выражения 2*а+b*с в виде дерева. Общие правила, связанные с определением приоритета операций. Три группы типов операторов. Приоритет аргумента. Множество предопределенных операторов. Одна из теорем де Моргана. Упражнения для повторения.

    презентация [17,3 K], добавлен 17.10.2013

  • Понятие матриц и операции, выполняемые с ними. Разработка программы для вычислений над матрицами в среде MS Visual Studio Express с применением языка программирования C++. Работа с библиотекой математического типа vector. Реализация перегрузки операций.

    курсовая работа [107,3 K], добавлен 22.12.2010

  • Понятие и характеристика операторов ввода и вывода информации, случаи их применяется в программах и основные виды: составной оператор Begin ... end, условный оператор If. Суть операторов безусловного перехода и циклических процессов, примеры применения.

    реферат [27,9 K], добавлен 03.03.2010

  • Переопределение метода внутри одного класса. Сущность перегрузки унаследованного метода. Области применения абстрактного класса. Перегрузка унарных и бинарных операций. Области видимости локальных и глобальных переменных. Способы обращения к ним.

    презентация [81,2 K], добавлен 09.12.2013

  • Анализ операторов ввода и вывода, а также характеристика форматов, используемых в этих операторах. Оформление законченной программы с применением этих операторов. Структура программы. Алфавит языка и типы данных. Ввод и вывод информации. Форматный вывод.

    лабораторная работа [62,0 K], добавлен 15.07.2010

  • Внутренний язык СУБД для работы с данными. Результат компиляции DDL-операторов. Описание DML-языка, содержащего набор операторов для поддержки основных операций манипулирования содержащимися в базе данными. Организация данных и управление доступом в SQL.

    лекция [131,0 K], добавлен 19.08.2013

  • Изображение класса на диаграмме UML. Инкапсуляция как средство защиты его внутренних объектов. Использование принципа полиморфизма для реализации механизма интерфейсов. Создание новых классов путем наследования. Ассоциация как вид отношений между ними.

    лекция [516,6 K], добавлен 03.12.2013

  • Сущность и основные свойства алгоритма, способы и методы описания. Линейные и ветвящиеся вычислительные процессы, характеристика и отличительные черты. Основные понятия языка Паскаль. Структура и компоненты программы. Назначение структурных операторов.

    контрольная работа [20,6 K], добавлен 13.09.2009

  • Понятие и функции комплексных чисел. Правила выполнения арифметических операций с комплексными числами. Действия с комплексными числами: сложение, вычитание, произведение, деление. Программная реализация решения задачи. Пример выполнения программы.

    курсовая работа [398,8 K], добавлен 01.02.2010

  • Алфавит, операторы языка С#. Понятие классов и объектов, модификаторы. Структура программного модуля. Практический пример заполнения матрицы. Программа нахождения первого отрицательного члена заданной последовательности, контрольный пример и блок-схема.

    курсовая работа [1,4 M], добавлен 04.01.2015

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.