Принципы объектно-ориентированного программирования: инкапсуляция, наследование, полиморфизм реализованные в языках C++ и С#. Три основных принципа языков объективно-ориентированного программирования


Скачать 443.61 Kb.
НазваниеПринципы объектно-ориентированного программирования: инкапсуляция, наследование, полиморфизм реализованные в языках C++ и С#. Три основных принципа языков объективно-ориентированного программирования
страница1/5
Дата публикации01.08.2013
Размер443.61 Kb.
ТипДокументы
userdocs.ru > Информатика > Документы
  1   2   3   4   5
Принципы объектно-ориентированного программирования: инкапсуляция, наследование, полиморфизм - реализованные в языках C++ и С#.

Три основных принципа языков объективно-ориентированного программирования

По Бьерну Страуструпу, автору C++, язык может называться объектно-ориентированным, если в нем реализованы три концепции: объекты, классы и наследование. Однако теперь принято считать, что такие языки должны держаться на других трех китах: инкапсуляции, наследовании и полиморфизме.

Инкапсуляция

Инкапсуляция, или утаивание информации (information hiding), — это возможность скрыть внутреннее устройство объекта от его пользователей, предоставив через интерфейс доступ только к тем членам объекта, с которыми клиенту разрешается работать напрямую. Необходимо пояснить разницу между абстрагированием и икапсуляцией. Инкапсуляция подразумевает наличие границы между внешним интерфейсом класса (открытыми членами, видимыми пользователям класса) и деталями его внутренней реализации. Преимущество инкапсуляции для разработчика в том, что он может открыть те члены класса, которые будут оставаться статичными, или неизменяемыми, скрыв внутреннюю организацию класса, более динамичную и в большей степени подверженную изменениям. В С# и С++ инкапсуляция достигается путем назначения члену класса модификатора доступа — public, private или protected.

Наследование

Наследованием называют возможность при описании класса указывать на его происхождение (kind-of relationship) от другого класса. Наследование позволяет создать новый класс, в основу которого положен существующий. В полученный таким образом класс можно внести свои изменения, а затем создать новые объекты данного типа. Этот механизм лежит в основе создания иерархии классов. После абстрагирования наследование — наиболее значимая часть общего планирования системы. Производным (derived class) называется создаваемый класс, производный от базового (base class). Производный класс наследует все методы базового, позволяя задействовать результаты прежнего труда.

Чтобы понять, когда и как применять наследование, вернемся к примеру EmployeeApp. Допустим, в компании есть служащие с разными типами оплаты труда: постоянный оклад, почасовая оплата и оплата по договору. Хотя у всех объектов Employee должен быть одинаковый интерфейс, их внутреннее функционирование может различаться. Например, метод CalculatePay для служащего на окладе будет работать не так, как для контрактника. Однако для ваших пользователей важно, чтобы интерфейс CalculatePay не зависел от того, как считается зарплата.

^ Что такое "правильное" наследование

Важнейшую проблему "правильного" наследования начнем с термина замещаемость (substitutability). Этот термин означает, что поведение производного класса достигается путем замещения поведения, заимствованного у базового класса. Это одно из важнейших правил, которое вам нужно соблюдать при построении работающей иерархии классов.

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

Полиморфизм

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

Предположим, вам нужно написать метод, в котором для каждого объекта из набора Employee вызывается метод CakulatePay. Все просто, если зарплата рассчитывается одним способом: вы можете сразу вставить в набор тип нужного объекта. Проблемы начинаются с появлением других форм оплаты. Допустим, у вас уже есть класс Employee, реализующий расчет зарплаты по фиксированному окладу. А что делать, чтобы рассчитать зарплату контрактников — ведь это уже другой способ расчета! В случае с процедурным языком вам пришлось бы переделать функцию, включив в нее новый тип обработки, так как в прежнем коде такой обработки нет. А объектно-ориентированный язык благодаря полиморфизму позволяет делать различную обработку.

В нашем примере надо описать базовый класс Employee, а затем создать производные от него классы для всех форм оплаты (упомянутых выше). Каждый производный класс будет иметь собственную реализацию метода CakulatePay. Здесь и начинается самое интересное. Возьмите указатель на объект, приведите его к типу-предку и вызовите метод этого объекта, а средства языка времени выполнения обеспечат вам, благодаря полиморфизму, вызов той версии этого метода, которая вам требуется.

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

Второе достоинство : старый код может использовать новый код. Заметьте: метод PolyApp.Calculate Pay перебирает в цикле элементы массива объектов Employee. Поскольку объекты приводятся неявно к вышестоящему типу Employee, а реализация полиморфизма во время выполнения обеспечивает вызов надлежащего метода, то ничто не мешает нам добавить в систему другие производные формы оплаты, вставить их в массив объектов Employee, и весь существующий код продолжит работу в своем первоначальном виде!

Абстрагирование

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

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

Однако язык — это один уровень абстрагирования. Если вы пойдете дальше, то, как разработчику класса, вам нужно придумать такую степень абстрагирования, чтобы клиенты вашего класса могли сразу сосредоточиться на своей задаче, не тратя время на изучение работы класса. На очевидный вопрос — какое отношение интерфейс класса имеет к абстрагированию? — можно ответить так: интерфейс класса и есть реализация абстрагирования.

При определении нужной степени абстрагирования класса важно помнить и о программисте клиентского кода. Представьте, что вы пишете основное ядро базы данных. Возможно, вы прекрасно разбираетесь в таких понятиях БД, как курсоры (cursors), управление фиксацией (commitment control) и кортежи (tuples). Однако многие разработчики, не столь искушенные в программировании БД, не собираются вникать в тонкости этих понятий. Используя терминологию, непонятную клиентам вашего класса, вы не достигнете основной цели абстрагирования — повысить эффективность работы программиста путем представления предметной области в понятных ему и естественных терминах.

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

^ О пользе абстрагирования

Наличие в классах абстрагирования, которое максимально удобно для программистов, работающих с этими классами, имеет первостепенное значение при разработке повторно используемого ПО. Если вы выстроите интерфейс, на который не влияют изменения в реализации, то вашему приложению долгое время не понадобятся никакие модификации. Вспомните пример с расчетом зарплаты. При работе с объектом Employee и функциями, обеспечивающими расчет зарплаты, клиенту нужны лишь несколько методов, таких как CalculatePay, GetAddress и GetEmployeeType. Если вы знакомы с предметной областью задачи, вы без труда определите, какие методы понадобятся пользователям класса. Скажем так: если при проектировании класса вам удается сочетать хорошее знание предметной области с прогнозом относительно дальнейших перспектив использования класса, можно гарантировать, что большая часть интерфейса этого класса останется неизменной, даже в случае возможного совершенствования реализации класса.

Поясним сказанное на примере.

using System;

class Employee

{

public Employee(string firstName, string lastName, int age, double payRate)

{

this.firstName = firstName;

this.lastName = lastName;

this.age = age;

this.payRate = payRate; }

protected string firstName;

protected string lastName;

protected int age;

protected double payRate;

public virtual double CalculatePay(int hoursWorked)

{

Console.WriteLine("Employee.CalculatePay"); return 42;

}

class SalariedEmployee : Employee {

public SalariedEmployee(string firstName, string lastName,

int age, double payRate) : base(firstName, lastName, age, payRate) {}

public override double CalculatePay(int hoursWorked) {

Console.WriteLine("SalariedEmployee.CalculatePay"); return 42; // произвольное число } } .
class ContractorEmployee : Employee {

public ContractorEmployee(string firstName, string lastName, int age, double payRate)

: base(firstName, lastName, age, payRate)}

public override double CalculatePay(int hoursWorked) {

Console.WriteLineC'ContractorEmployee.CalculatePay");

return 42; // произвольное число } }

class HourlyEmployee : Employee {

public HourlyEmployee(string firstName, string lastName, int age, double payRate)

: base(firstName, lastName, age, payRate){}

public override double CalculatePay(int hoursWorked)

Console.WriteLine("Hou rlyEmployee.CalculatePay");

return 42; // произвольное число }class PolyApp {

protected Employee[] employees;

protected void LoadEmployeesQ

{

Console.WriteLine("Загрузка информации о сотрудниках...");

// В реальном приложении эти сведения мы // возьмем, наверное, из базы данных, employees = new Employee[3];

employees[0] = new SalariedEmployee ("Amy", "Ariderson", 28, 100);

employees[1] = new ContractorEmployee ("John", "Maffei", 35, 110); employees[2] = new HourlyEmployee ("Lani", "Ota", 2000, 5);

Console. Writel_ine( "\n"); }

protected void CalculatePayO .

{foreach(Employee emp in employees)

emp.CalculatePay(40);

} }

public static void Main()

{PolyApp app = new PolyAppQ;

app.LoadEmployees(); app. CalculatePayO; } }

^ Использование обобщенных (шаблонных) типов в языках С++иС#. Обзор библиотеки STL.

Шаблоны типа

Зачем программисту может понадобиться определить такой тип, как вектор целых чисел? Как правило, ему нужен вектор из элементов, тип которых неизвестен создателю класса Vector. Следовательно, надо суметь определить тип вектора так, чтобы тип элементов в этом определении участвовал как параметр, обозначающий "реальные" типы элементов:

template < class T > class Vector // вектор элементов типа T

{ T * v;

int sz;

public:

Vector ( int s )

{ if ( s <= 0 )

error ( "недопустимый для Vector размер" );

v = new T [ sz = s ]; // выделить память для массива s типа T

}

T & operator [] ( int i );

int size () { return sz; }};

Таково определение шаблона типа. Он задает способ получения семейства сходных классов. Это описание отличается от обычного описания класса наличием начальной конструкции template, которая и показывает, что описывается не класс, а шаблон типа с заданным параметром-типом.

void f ()

{ Vector < int > v1 ( 100 ); // вектор из 100 целых

Vector < complex > v2 ( 200 ); // вектор из 200 комплексных чисел

v2 [ i ] = complex ( v1 [ x ], v1 [ y ] );}

^ Синтаксис описания шаблона

Шаблон функции начинается с ключевого слова template, за которым в угловых скобках следует список параметров. Затем следует объявление функции:

template< typename T >

void sort( T array[], int size ); // шаблон sort объявлен, но не определён

template< typename T >

void sort( T array[], int size ) { /* сортировка */} // объявление и определение

template< int BufferSize > // целочисленный параметр

char* read()

{ char *Buffer = new char[ BufferSize ]; /* считывание данных */

return Buffer;}

Ключевое слово typename появилось сравнительно недавно, поэтому стандарт допускает использование class вместо typename:

template< class T >

^ Шаблоны классов

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

template< class T >

class List

{public:

void Add( const T& Element );

bool Find( const T& Element );};

Использование шаблонов

Для использования шаблона класса, необходимо указать его параметры:

List li;

List ls;

^ Различия между шаблонами языка C++ и универсальными шаблонами языка C#

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

Ниже приведены основные различия между шаблонами языка C++ и C#:

  • Универсальные шаблоны языка C# не обеспечивают такую же гибкость, как шаблоны языка C++.

  • Язык C# не позволяет использовать не являющиеся типами параметры шаблона.

  • Язык C# не поддерживает явную специализацию, т.е. индивидуальную реализацию шаблона для конкретного типа.

  • Язык C# не поддерживает частичную специализацию: индивидуальную реализацию для подмножества аргументов типа.

  • Язык C# не позволяет использовать параметр типа в качестве базового класса для универсального типа.

  • Язык C# не позволяет параметрам типов иметь типы по умолчанию.

  • В языке C# параметр универсального типа не может сам быть универсального типа, хотя сконструированные типы могут использоваться как универсальные. Язык C++ не допускает использование параметров шаблона.

  • Язык C++ позволяет использование кода, который может быть допустимым не для всех параметров типа в шаблоне и который затем проверяется для конкретного типа, используемого в качестве параметра типа. В языке C# код класса должен быть написан таким образом, чтобы он работал с любым типом, удовлетворяющим требования существующих ограничений. Допускаются только те языковые конструкции, которые могут быть выведены из ограничений.

  1   2   3   4   5

Похожие:

Принципы объектно-ориентированного программирования: инкапсуляция, наследование, полиморфизм реализованные в языках C++ и С#. Три основных принципа языков объективно-ориентированного программирования icon Списки вопросов по дисциплинам, вынесенным на экзамен
...
Принципы объектно-ориентированного программирования: инкапсуляция, наследование, полиморфизм реализованные в языках C++ и С#. Три основных принципа языков объективно-ориентированного программирования iconСетка часов. 10а класс
Использование информационных моделей с использованием систем объектно-ориентированного программирования и электронных таблиц
Принципы объектно-ориентированного программирования: инкапсуляция, наследование, полиморфизм реализованные в языках C++ и С#. Три основных принципа языков объективно-ориентированного программирования iconТема 1: Эволюция языков программирования
Процедурное программирование, Объектно-ориентированное программирование (ооп), Декларативные языки программирования
Принципы объектно-ориентированного программирования: инкапсуляция, наследование, полиморфизм реализованные в языках C++ и С#. Три основных принципа языков объективно-ориентированного программирования iconПонятие программы и программирования. Свойства программ. Назначение...
Системы счисления. Сущность перевода чисел из одной системы счисления в другую: примеры
Принципы объектно-ориентированного программирования: инкапсуляция, наследование, полиморфизм реализованные в языках C++ и С#. Три основных принципа языков объективно-ориентированного программирования iconИсторический обзор развития методологии объектно-ориентированного...

Принципы объектно-ориентированного программирования: инкапсуляция, наследование, полиморфизм реализованные в языках C++ и С#. Три основных принципа языков объективно-ориентированного программирования iconВопросы к экзамену по курсу "Технологии программирования" для потока ас-09
Обзор основных моделей программирования. Императивное (процедурное) программирование (пример программы на Pure c или Pascal)
Принципы объектно-ориентированного программирования: инкапсуляция, наследование, полиморфизм реализованные в языках C++ и С#. Три основных принципа языков объективно-ориентированного программирования icon1 Методология процедурно-ориентированного программирования
Выбор платформы и операционной системы, как правило, не являлся серьезной проблемой. А сопровождение программы, хотя и было сопряжено...
Принципы объектно-ориентированного программирования: инкапсуляция, наследование, полиморфизм реализованные в языках C++ и С#. Три основных принципа языков объективно-ориентированного программирования iconВведение в конфигурирование в системе "1С: Предприятие 8". Основные объекты
Курс предназначен для подготовки специалистов по конфигурированию в системе "1С: Предприятие 8". Курс является базовым. Рекомендуется...
Принципы объектно-ориентированного программирования: инкапсуляция, наследование, полиморфизм реализованные в языках C++ и С#. Три основных принципа языков объективно-ориентированного программирования iconТаблицы решений в реализации задач финансово-экономического управления
При этом единственным наследием, доставшимся пользователям электронных таблиц от программирования задач на высокоуровневых языках,...
Принципы объектно-ориентированного программирования: инкапсуляция, наследование, полиморфизм реализованные в языках C++ и С#. Три основных принципа языков объективно-ориентированного программирования iconЛабораторная работа №1 Среда программирования Visual C++. Программирование линейных алгоритмов 6
Б 92 Основы алгоритмизации и программирования в среде Visual C++ : лаб практикум по курсу «Основы алгоритмизации и программирования»...
Вы можете разместить ссылку на наш сайт:
Школьные материалы


При копировании материала укажите ссылку © 2015
контакты
userdocs.ru
Главная страница