Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
билеты(30-40.docx
Скачиваний:
6
Добавлен:
03.08.2019
Размер:
385 Кб
Скачать
☆

Implementation // раздел реализации

…

function TCircle. Area: Real; // метода Area класса TRing

begin

Result:= inherited Area – Pi * FR2 * FR2; // расчет площади кольца

end;

Обратите внимание на директиву Inherited, которая позволяет вызвать метод предка. В данном примере, выполнив inherited Area, мы получили площадь внешней окружности, при этом отпала необходимость повторять реализацию метода предка.

Полиморфизм

В значительной степени мощь объектно-ориентированного программирования проистекает из применения различных форм полиморфизма. Слово полиморфизм греческого происхождения и означает приблизительно «много форм».

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

Например, выше мы рассмотрели пример класса TCircle и дочернего от него класса TRing. Согласно правилу соответствия типов, переменные дочернего класса всегда совместимы с переменными класса-предка, причем совместимость односторонняя: переменной класса-предка можно присвоить значение переменной дочернего класса, но не наоборот. Например, есть объявленная переменная класса TCircle, которой присваивается фактический параметр класса TRing, оба класса имеют методы с одинаковым названием, но разной реализацией. Концепция полиморфизма подразумевает, что будут вызываться методы, соответствующие не типу объявленной переменной, а типу реально записанной в нее переменной. (см. пример «методы виртуальные и динамические»)

35. Методы

Процедуры и функции, предназначенные для выполнения над объектами действий, называются методами. Предварительное объявление методов выполняется при описании класса в секции interface модуля, а их программный код записывается в секции implementation. Однако в отличие от обычных процедур и функций заголовки методов должны иметь уточненные имена, т.е. содержать наименование класса. Приведем возможную реализацию одного из методов в классе TDelimitedReader:

procedure TDelimitedReader.SetActive(const AActive: Boolean);

begin

if AActive then

Reset(FileVar) // Открытие файла

else

CloseFile(FileVar); // Закрытие файла

end;

Обратите внимание, что внутри методов обращения к полям и другим методам выполняются как к обычным переменным и подпрограммам без уточнения экземпляра объекта. Такое упрощение достигается путем использования в пределах метода псевдопеременной Self (стандартный идентификатор). Физически Self представляет собой дополнительный неявный параметр, передаваемый в метод при вызове. Этот параметр и указывает экземпляр объекта, к которому данный метод применяется. Чтобы пояснить сказанное, перепишем метод SetActive, представив его в виде обычной процедуры:

procedure TDelimitedReader_SetActive(Self: TDelimitedReader;

const AActive: Boolean);

begin

if AActive then

Reset(Self.FileVar) // Открытие файла

else

CloseFile(Self.FileVar); // Закрытие файла

end;

Согласитесь, что метод SetActive выглядит лаконичнее процедуры TDelimitedReader_SetActive.

Практика показывает, что псевдопеременная Self редко используется в явном виде. Ее необходимо применять только тогда, когда при написании метода может возникнуть какая-либо двусмысленность для компилятора, например при использовании одинаковых имен и для локальных переменных, и для полей объекта.

Если выполнить метод SetActive,

Reader.SetActive(True);

то обрабатываемый файл будет открыт. При этом неявный параметр Self будет содержать значение переменной Reader. Такой вызов реализуется обычными средствами процедурного программирования приблизительно так:

TDelimitedReader_SetActive(Reader, True);

36. Насле́дование — механизм объектно-ориентированного программирования (наряду с инкапсуляцией, полиморфизмом и абстракцией), позволяющий описать новый класс на основе уже существующего (родительского), при этом свойства и функциональность родительского класса заимствуются новым классом.

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

C++

Наследование в C++:

class A{ //базовый класс

};

class B : public A{ //public наследование

};

class C : protected A{ //protected наследование

};

class Z : private A{ //private наследование

};

В C++ существует три типа наследования: public, protected, private. Спецификаторы доступа членов базового класса меняются в потомках следующим образом:

ANSI ISO IEC 14882 2003

Если класс объявлен как базовый для другого класса со спецификатором доступа public, тогда public члены базового класса доступны как public члены производного класса, protected члены базового класса доступны как protected члены производного класса.

Если класс объявлен как базовый для другого класса со спецификатором доступа protected, тогда public и protected члены базового класса доступны как protected члены производного класса.

Если класс объявлен как базовый для другого класса со спецификатором доступа private, тогда public и protected члены базового класса доступны как private члены производного класса.

\ANSI ISO IEC 14882 2003

Одним из основных преимуществ public-наследования является то, что указатель на классы-наследники может быть неявно преобразован в указатель на базовый класс, то есть для примера выше можно написать:

A* a = new B;

Эта интересная особенность открывает возможность динамической идентификации типа (RTTI).

[править]Delphi (Object Pascal)

Для использования механизма наследования в Delphi необходимо в объявлении класса справа от слова class указать класс предок:

Предок:

TAncestor = class

private

protected

public

// Виртуальная процедура

procedure VirtualProcedure; virtual; abstract;

procedure StaticProcedure;

end;

Наследник:

TDescendant = class(TAncestor)

private

protected

public

// Перекрытие виртуальной процедуры

procedure VirtualProcedure; override;

procedure StaticProcedure;

end;

Абсолютно все классы в Delphi являются потомками класса TObject. Если класс-предок не указан, то подразумевается, что новый класс является прямым потомком класса TObject.

Множественное наследование в Delphi частично поддерживается за счёт использования классов-помощников (Сlass Helpers).

[править]Python

Python поддерживает как одиночное, так и множественное наследование. При доступе к атрибуту порядок просмотра производных классов называется порядком разрешения метода [1](англ. method resolution order).

class Ancestor1(object): # Предок 1

def m1(self): pass

class Ancestor2(object): # Предок 2

def m1(self): pass

class Descendant(Ancestor1, Ancestor2): # Наследник

def m2(self): pass

d = Descendant() # инстанциация

print d.__class__.__mro__ # порядок разрешения метода:

(<class '__main__.Descendant'>, <class '__main__.Ancestor1'>, <class '__main__.Ancestor2'>, <type 'object'>)

С версии Python 2.2 в языке сосуществуют «классические» классы и «новые» классы. Последние являются наследниками object. «Классические» классы будут поддерживаться вплоть до версии 2.6, но удалены из языка в Python версии 3.0.

Множественное наследование применяется в Питоне, в частности, для введения в основной класс классов-примесей (mix-in).

[править]PHP

Для использования механизма наследования в PHP необходимо в объявлении класса после имени объявляемого класса-наследника указать слово extends и имя класса-предка:

class Descendant extends Ancestor {

}

В случае перекрытия классом-наследником свойств и методов предка, доступ к свойствам и методам предка можно получить с использованием ключевого слова parent:

class A {

function example() {

echo "Вызван метод A::example().<br />\n";

}

}

class B extends A {

function example() {

echo "Вызван метод B::example().<br />\n";

parent::example();

}

}

[править]Objective-C

@interface MyNumber : NSObject {

int num;

}

- (int) num;

- (void) setNum: (int) theNum;

@end

@implementation

- (id) init {

self = [super init];

return self;

}

- (int) num {

return num;

}

- (void) setNum: (int) theNum {

num = theNum;

}

@end

Переопределенные методы не нужно объявлять в интерфейсе.

[править]C#

Пример наследования от одного класса и двух интерфейсов:

public class A { }

public interface I1 { }

public interface I2 { }

public class B : A, I1, I2 { }

Наследование от типизированных классов можно осуществлять, указав фиксированный тип, либо путем переноса переменной типа в наследуемый класс:

public class A<T>

{ }

public class B : A<int>

{ }

public class B2<T> : A<T>

{ }

Допустимо также наследование вложенных классов от классов, их содержащих:

class A

{

public class B : A { }

}

Директива sealed в объявлении класса делает наследование от него невозможным.[2]

[править]Ruby

class Parent

def public_method

"Public method"

end

private

def private_method

"Private method"

end

end

class Children < Parent

def public_method

"Redefined public method"

end

def call_private_method

"Ancestor's private method: " + private_method

end

end

Класс Parent является предком для класса Children, у которого переопределен метод public_method.

children = Children.new

children.public_method #=> "Redefined public method"

children.call_private_method #=> "Ancestor's private method: Private method"

Приватные методы предка можно вызывать из наследников.

37.

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

1. Анализ и формирование требований. Путем консультаций с заказчиком ПО определяются функциональные возможности, ограничения и цели создаваемой программ­ной системы.

2. Проектирование системы и программного обеспечения. Процесс проектирования систе­мы разбивает системные требования на требования, предъявляемые к аппаратным средствам, и требования к программному обеспечению системы. Разрабатывается общая архитектура системы. Проектирование ПО предполагает определение и описание основных программных компонентов и их взаимосвязей.

3. Кодирование и тестирование программных модулей. На этой стадии архитектура ПО реа­лизуется в виде множества программ или программных модулей. Тестирование каж­дого модуля включает проверку его соответствия требованиям к данному модулю.

4. Сборка и тестирование системы. Отдельные программы и программные модули ин­тегрируются и тестируются в виде целостной системы. Проверяется, соответствует ли система своей спецификации,

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

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

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

Последний этап жизненного цикла ПО (эксплуатация и сопровождение) — это "полноценное" использование программной системы. На этом этапе могут обнаружиться ошибки, допущенные, например, на первом этапе формирования требований. Могут также проявиться ошибки проектирования и кодирования, что может потребовать определения но­вых функциональных возможностей системы. С другой стороны, система постоянно должна оставаться работоспособной. Внесение необходимых изменений в программную систему мо­жет потребовать повторения некоторых или даже всех этапов процесса создания ПО.

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