Абстрактный класс. Чисто виртуальные функции

Чисто виртуальная функция (pure virtual function) является функцией, которая объявляется в базовом классе, но не имеет в нем определения. Поскольку она не имеет определения, то есть
тела в этом базовом классе, то всякий производный класс обязан иметь свою собственную версию определения. Для объявления чисто виртуальной функции используется следующая общая форма:

virtual тип имя_функции(список параметров) = 0;

Здесь тип обозначает тип возвращаемого значения, а имя_функции является именем функции. На­пример, следующая версия функции show_area() класса figure является чисто виртуальной функцией.

class figure {
double х, у;
public:
void set_dim(double i, double j=0) {
x = i;
y = j;
}
virtual void show_area() = 0; // чисто виртуальная
};

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

/* Данная программа не компилируется, поскольку класс circle не переопределил show_агеа() */
#include <iostream.h>
class figure {
protected:
double x, y;
public:
void set_dim(double i, double j) {
x = i;
у = j;
}
virtual void show_area() = 0; // pure
};
class triangle: public figure {
public:
void show_area() {
cout << "Triangle with height ";
cout << x << " and base " << y;
cout << " has an area of ";
cout << x * 0.5 * у << ". \ n";
}
};
class square: public figure {
public:
void show_area() {
cout << "Square with dimensions ";
cout << x << "x" << y;
cout << " has an area of ";
cout << x * у << ". \n";
}
};
class circle: public figure {
// определение show_area() отсутствует и потому выдается ошибка
};
int main ()
{
figure *р; // создание указателя базового типа
circle с; // попытка создания объекта типа circle - ОШИБКА
triangle t; // создание объектов порожденных типов
square s;
p = &t;
p->set_dim(10.0, 5.0);
p->show_area ();
p = &s;
p->set_dim(10.0, 5.0);
p->show_area();
return 0;
}

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

35.Множественное наследование в С++. Прямая и косвенная база. Исключение дублирования членов в производных классах..

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

//Листинг 7. Пример множественного наследования

class A

{int a1;

public:

int a2;

void funcA()

};

class B

{int b1;

public:

int b2;

void funcB()

};

class C: public A, public B //наследуем класс С от A и B

{int c1;

public:

int c2;

void funcC()

};

Схема иерархии классов, определенных в последнем примере, изображена на рис.4

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

class A {public: int x; void funcA(); …};

class B: public A {…};

class D: public A{…};

class C: public B, public D {…};

Дублирование косвенного базового класса (рис 5а) приводит к включению в производный класс нескольких объектов базового класса. Для класса С в последнем примере это означает, что компонентное данное x будет существовать в объектах данного класса в двух экземплярах – один унаследован через класс В, другой – через класс D, что порождает проблему неоднозначности при доступе к дублирующимся компонентам класса: неясно, какой из одноименных компонент изменится при следующем обращении

main()

{ C c;

c.x=6; // Ошибка!!!

}

Попытка доступа к члену данных x для объекта с приводит к ошибке транслятора “Member is ambiguous A::x and A::x”. Эта ошибка означает, что транслятор не может определить, какому из двух компонент x класса необходимо присвоить новое значение. Неразрешимыми именами для транслятора будут также следующие с.C::x и c.A::x. Решением проблемы является использование квалифицированных имен компонент с использованием имен классов B и D. Для транслятора однозначно различаются следующие имена компонент: с.B::x (компонента, унаследованная через класс В) и c.D::x (компонента, унаследованная через класс D). Именно из-за сложности управления одноименными унаследованными компонентами класса множественное наследование реализаций было запрещено в языках программирования, появившихся после С++ (например, в C# и Java).

Еще один вариант множественного наследования классов в языке С++ - использование виртуальных базовых классов. Если компоненты косвенного базового класса не должны дублироваться в классе-потомке, то он объявляется виртуальным:

class D {…};

class A: public virtual D {…};

class B: public virtual D {…};

class C: public A, public B{…};

Диаграмма классов в этом случае будет выглядеть как на рис. 5б. Компоненты косвенного базового класса присутствуют в классе С в единственном экземпляре, проблемы неоднозначности доступа к ним не возникает.

36. Шаблоны классов. Форматы описания шаблона класса, методов и объектов шаблонного класса.

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

Шаблоны классов часто наз-т параметризованными типами, так как они имеют один или большее кол-во параметров типа, определяющих настройку родового шаблона класса на специфический тип данных при создании объекта класса.

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

Для того, чтобы использовать шаблонные классы, достаточно один раз описать шаблон класса. Шаблон класса Stack, например, может служить основой для создания многочисленных классовStackнеобходимых программе типов (таких, например, как *Stackдля данных типаfloat>>, <*Stackдля данных типаint*, <<Stackдля данных типаchar* и т. д.).

template<classT>

Class name

Идентификатор Т определяет тип данных-элементов, хранящихся в стеке, и может использоваться в заголовке класса Stack и в функциях-элементах.

Формат описания шаблонного класса следующий

template <class T,int N>

class Massiv

{

Massive();

~Massive();

};

Т является обозначением передаваемого в шаблон класса (типа данных). Служебное слово класс является признаком того, передаваемый в класс параметр- тип данных. Обозначение конкретного типа данных слева от передаваемого параметра означает, что данных параметр является константой. Например, шаблонный класс Massiv предназначен для организации классов массивов из элементов данных типа Т с количеством элементов N. Для организации класса массивов, состоящих из фиксированного количества элементов конкретного типа целесообразно использовать операцию typedef. Например, для описания класса массива целых чисел из 20 элементов следует использовать команду typedef Massive MassiveInt20; Далее можно определять конкретный массив MassiveInt20 M1; Возможен вариант определения массива непосредственно на основе шаблона Massive M2; Полное определение функций шаблона должно выглядеть следующим образом

template <class T, int N>

Massive<T,N>::Massive()

{

}
37. Понятие программного обеспечения.


Вся совокупность программ, хранящихся на всех устройствах долговременной памятикомпьютера, составляет его программное обеспечение (ПО).

38.Жизненный цикл программы.

Жизненный цикл программного обеспечения (ПО) — период времени, который начинается с момента принятия решения о необходимости создания программного продукта и заканчивается в момент его полного изъятия из эксплуатации

Модели жизненного цикла ПО[править | править вики-текст]

Водопадная (каскадная, последовательная) модель [править | править вики-текст]

Основная статья: Модель водопада

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

Этапы проекта в соответствии с каскадной моделью:

1. Формирование требований;

2. Проектирование;

3. Реализация;

4. Тестирование;

5. Внедрение;

6. Эксплуатация и сопровождение.

Преимущества:

· Полная и согласованная документация на каждом этапе;

· Легко определить сроки и затраты на проект.

Недостатки:

В водопадной модели переход от одной фазы проекта к другой предполагает полную корректность результата (выхода) предыдущей фазы. Однако неточность какого-либо требования или некорректная его интерпретация в результате приводит к тому, что приходится «откатываться» к ранней фазе проекта и требуемая переработка не просто выбивает проектную команду из графика, но приводит часто к качественному росту затрат и, не исключено, к прекращению проекта в той форме, в которой он изначально задумывался. По мнению современных специалистов, основное заблуждение авторов водопадной модели состоит в предположениях, что проект проходит через весь процесс один раз, спроектированная архитектура хороша и проста в использовании, проект осуществления разумен, а ошибки в реализации легко устраняются по мере тестирования. Эта модель исходит из того, что все ошибки будут сосредоточены в реализации, а потому их устранение происходит равномерно во время тестирования компонентов и системы[2]. Таким образом, водопадная модель для крупных проектов мало реалистична и может быть эффективно использована только для создания небольших систем[3].

Итерационная модель [править | править вики-текст]

Альтернативой последовательной модели является так называемая модель итеративной и инкрементальной разработки (англ. iterative and incremental development, IID), получившей также от Т. Гилба в 70-е гг. название эволюционной модели. Также эту модель называют итеративной моделью и инкрементальной моделью [4].

Модель IID предполагает разбиение жизненного цикла проекта на последовательность итераций, каждая из которых напоминает «мини-проект», включая все процессы разработки в применении к созданию меньших фрагментов функциональности, по сравнению с проектом в целом. Цель каждой итерации — получение работающей версии программной системы, включающей функциональность, определённую интегрированным содержанием всех предыдущих и текущей итерации. Результат финальной итерации содержит всю требуемую функциональность продукта. Таким образом, с завершением каждой итерации продукт получает приращение — инкремент — к его возможностям, которые, следовательно, развиваются эволюционно. Итеративность, инкрементальность и эволюционность в данном случае есть выражение одного и того же смысла разными словами со слегка разных точек зрения[3].

По выражению Т. Гилба, «эволюция — прием, предназначенный для создания видимости стабильности. Шансы успешного создания сложной системы будут максимальными, если она реализуется в серии небольших шагов и если каждый шаг заключает в себе четко определённый успех, а также возможность «отката» к предыдущему успешному этапу в случае неудачи. Перед тем, как пустить в дело все ресурсы, предназначенные для создания системы, разработчик имеет возможность получать из реального мира сигналы обратной связи и исправлять возможные ошибки в проекте»[4].

Подход IID имеет и свои отрицательные стороны, которые, по сути, — обратная сторона достоинств. Во-первых, целостное понимание возможностей и ограничений проекта очень долгое время отсутствует. Во-вторых, при итерациях приходится отбрасывать часть сделанной ранее работы. В-третьих, добросовестность специалистов при выполнении работ всё же снижается, что психологически объяснимо, ведь над ними постоянно довлеет ощущение, что «всё равно всё можно будет переделать и улучшить позже»[3].

Различные варианты итерационного подхода реализованы в большинстве современных методологий разработки (RUP, MSF, XP).

Спиральная модель [править | править вики-текст]

Спиральная модель (англ. spiral model) была разработана в середине 1980-х годов Барри Боэмом. Она основана на классическом цикле Деминга PDCA (plan-do-check-act). При использовании этой модели ПО создается в несколько итераций (витков спирали) методом прототипирования.

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

На каждой итерации оцениваются:

· риск превышения сроков и стоимости проекта;

· необходимость выполнения ещё одной итерации;

· степень полноты и точности понимания требований к системе;

· целесообразность прекращения проекта.

Важно понимать, что спиральная модель является не альтернативой эволюционной модели (модели IID), а специально проработанным вариантом. К сожалению, нередко спиральную модель либо ошибочно используют как синоним эволюционной модели вообще, либо (не менее ошибочно) упоминают как совершенно самостоятельную модель наряду с IID[3].

Отличительной особенностью спиральной модели является специальное внимание, уделяемое рискам, влияющим на организацию жизненного цикла, и контрольным точкам. Боэм формулирует 10 наиболее распространённых (по приоритетам) рисков:

1. Дефицит специалистов.

2. Нереалистичные сроки и бюджет.

3. Реализация несоответствующей функциональности.

4. Разработка неправильного пользовательского интерфейса.

5. Перфекционизм, ненужная оптимизация и оттачивание деталей.

6. Непрекращающийся поток изменений.

7. Нехватка информации о внешних компонентах, определяющих окружение системы или вовлеченных в интеграцию.

8. Недостатки в работах, выполняемых внешними (по отношению к проекту) ресурсами.

9. Недостаточная производительность получаемой системы.

10. Разрыв в квалификации специалистов разных областей.

39.Проблемы проектирования сложных программных средств.

Проблемы разработки ПО

Наиболее распространёнными проблемами, возникающими в процессе разработки ПО, считают:

· Недостаток прозрачности. В любой момент времени сложно сказать, в каком состоянии находится проект и каков процент его завершения.
Данная проблема возникает при недостаточном планировании структуры (или архитектуры) будущего программного продукта, что чаще всего является следствием отсутствия достаточного финансирования проекта: программа нужна, сколько времени займёт разработка, каковы этапы, можно ли какие-то этапы исключить или сэкономить — следствием этого процесса является то, что этап проектирования сокращается.

· Недостаток контроля. Без точной оценки процесса разработки срываются графики выполнения работ и превышаются установленные бюджеты. Сложно оценить объём выполненной и оставшейся работы.
Данная проблема возникает на этапе, когда проект, завершённый более чем наполовину, продолжает разрабатываться после дополнительного финансирования без оценки степени завершённости проекта.

· Недостаток трассировки.

· Недостаток мониторинга. Невозможность наблюдать ход развития проекта не позволяет контролировать ход разработки в реальном времени. С помощью инструментальных средств менеджеры проектов принимают решения на основе данных, поступающих в реальном времени.
Данная проблема возникает в условиях, когда стоимость обучения менеджмента владению инструментальными средствами сравнима со стоимостью разработки самой программы.

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

· Недостаточная надёжность. Самый сложный процесс — поиск и исправление ошибок в программах на ЭВМ. Поскольку число ошибок в программах заранее неизвестно, то заранее неизвестна и продолжительность отладки программ и отсутствие гарантий отсутствия ошибок в программах. Следует отметить, что привлечение доказательного подхода к проектированию ПО позволяет обнаружить ошибки в программе до её выполнения. В этом направлении много работали Кнут, Дейкстра и Вирт. Профессор Вирт при разработке Паскаля и Оберона за счет строгости их синтаксиса добился математической доказуемости завершаемости и правильности программ, написанной на этих языках.
Данная проблема возникает при неправильном выборе средств разработки. Например, при попытке создать программу, требующую средств высокого уровня, с помощью средств низкого уровня. Например, при попытке создать средства автоматизации с СУБД на ассемблере. В результате исходный код программы получается слишком сложным и плохо поддающимся структурированию.

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

· Отсутствие гарантий качества и надежности программ из-за отсутствия гарантий отсутствия ошибок в программах вплоть до формальной сдачи программ заказчикам.
Данная проблема не является проблемой, относящейся исключительно к разработке ПО. Гарантия качества — это проблема выбора поставщика товара (не продукта).


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: