Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Множественное наследование против вложения



 

Является ли объект суммой его частей? Имеет ли смысл классы деталей автомобиля, такие Руль, Двери и Колеса, производить от общего класса Автомобиль, как показано на рис. 18.14?

 

Рис. 18.14. Возможно, но не умно

 

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

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

 

 

Рис. 18.15. Модель агрегирования

 

На рис. 18.16 показана модель композиции. Эта модель сообщает нам, что класс " тело" не только включает в себя (что можно было бы реализовать агрегированием) голову, две руки и две ноги, но что эти объекты (голова, руки и ноги) будут созданы при создании тела и исчезнут вместе с ним. Иными словами, они не имеют независимого существования.

 

Рис. 18.16. Модель композиции

 

Дискриминаторы и силовые классы

 

Как можно спроектировать производство разных моделей автомобилей одной марки? Предположим, вас наняла фирма Acme Motors, которая производит пять автомобилей: Pluto (компактный малолитражный автомобиль для поездок за покупками), Venus (четырехдверный " седан" с двигателем средней мощности), Mars (спортивный автомобиль типа " купе" с наиболее мощным двигателем, рассчитанный на максимальную скорость), Jupiter (мини-фургон с форсированным двигателем как у спортивного купе, правда, менее скоростной, зато более мощный) и Earth (маломощный, но скоростной фургон).

Можно было бы просто произвести все эти модели от общего класса Car, как показано на рис. 18.17.

 

 

Рис. 18.17. Обобщение подклассов всех моделей в общий базовый класс

 

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

 

Рис. 18.18. Модель отношения дискриминаторов

 

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

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

enum BodyType={sedan, coupe, minivan, stationwagon}

Однако далеко не каждый дискриминатора можно объявить, просто назвав его. Например, назначение определяется многими параметрами. В таком случае дискриминатор можно смоделировать как класс, и разные типы дискриминатора будут возвращаться как объекты класса.

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

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

Обычно в программах на C++ использование силовых классов реализуется с помощью указателей. Так, в нашем примере класс Car (соответствующий классу проекта Автомобиль) будет содержать указатель на объект класса PerformanceCharacteristics (рис. 18.20). Если хотите потренироваться, создайте самостоятельно силовые классы для дискриминаторов Кузов (body) и Двигатель (engine).

Class Car: public Vehicle

{

public:

Car();

~Car();

//другие открытые методы опущены

private:

PerformanceCharacteristics*pPerformance;

};

И наконец, силовые классы дают возможность создавать новые типы данных во время выполнения программы.

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

 

Динамическая модель

 

В модели проекта важно указать не только отношения между классами, но и принципы их взаимодействия. Например, классы Расчетный счет, ATM и Квитанция взаимодействуют с классом Клиент в ситуации Снятие со счета. Возвращаясь к виду последовательных диаграмм, которые использовались в начале анализа (см. рис. 18.11), рассмотрим теперь взаимодействие классов на основе определенных для них методов, как показано на рис. 18.21.

 

Рис. 18.19. Дискриминатор как силовой класс

 

 

Рис. 18.20. Отношение между объектом класса Автомобиль и связанным с ним силовым классом

 

 

Рис. 18.21. Диаграмма взаимодействия классов

 

Эта простая диаграмма показывает взаимодействие между несколькими классами проекта при определенной ситуации использования программы. Предполагается, что класс ATM делегирует классу Расчетный счет ответственность за учет остатка денег на счете, в то время как Расчетный счет делегирует классу ATM ответственность за доведение этой информации пользователю.

Существует два вида диаграмм взаимодействий классов. На рис. 18.21 показана диаграмма последовательности действий. Та же ситуация, но в другом виде, изображена на рис. 18.22 и называется диаграммой сотрудничества. Диаграмма первого типа определяет последовательность событий за некоторое время, а диаграмма второго типа — принципы взаимодействия классов. Диаграмму сотрудничества можно создать прямо из диаграммы последовательности. Такие средства, как Rational Rose, автоматически выполнят это задание после щелчка на кнопке.

 

Рис. 18.22. Диаграмма сотрудничества

Диаграммы переходов состояний

 

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

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

 

Сверхсостояния

 

Клиент может в любое время передумать и не регистрироваться. Он может это сделать после того, как вставил карточку или после ввода пароля. В любом случае система должна принять его запрос на аннулирование и вернуться в состояние Не зарегистрирован (рис. 18.24).

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

Диаграмма на рис. 18.25 дает ту же информацию, что и на рис. 18.24, но намного яснее и легче для чтения. В любой момент от начала регистрации и вплоть до ее завершения процесс можно отменить. Если вы это сделаете, то вернетесь в состояние Не зарегистрирован.

 

Рис. 18.23. Переходы состояний класса Расчетный счет

 

 

Рис. 18.24. Отмена регистрации

 

 

Рис. 18.25. Сверхсостояние

 

Резюме

 

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

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

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

 

Вопросы и ответы

 

Чем объектно-ориентированный анализ и проектирование фундаментально отличаются от других подходов?

До разработки объектно-ориентированной технологии аналитики и программисты были склонны думать о программах как о группах функций, работающих с данными. Объектно-ориентированное программирование рассматривает интегрированные данные и функции как самостоятельные единицы, содержащие в себе и данные, и методы манипулирования ими. При процедурном программирование внимание сконцентрировано на функциях и их работе с данными. Говорят, что программы на Pascal и С — коллекции процедур, а программы на C++ — коллекции классов.

Является ли объектно-ориентированное программирование той палочкой-выручалочкой, которая решит все проблемы программирования?

Нет, этого никогда и не ждали. Однако на современном уровне требования к программным продуктам объектно-ориентированные анализ, проектирование и программирование обеспечивают программистов средствами, которые не могло предоставить процедурное программирование.

Является ли C++ совершенным объектно-ориентированным языком?

C++, если сравнивать его с другими альтернативными объектно-ориентированными языками программирования, имеет множество преимуществ и недостатков. Но одно из безусловных преимуществ состоит в том, что это самый популярный объектно-ориентированный язык программирования на Земле. Откровенно говоря, большинство программистов решают работать на C++ не после изнурительного анализа альтернативных объектно-ориентированных языков. Они идут туда, где происходят основные события, а в 90-х основные события в мире программирования связаны с C++. Тому есть веские причины. Конечно, C++ может многое предложить программисту, но эта книга существует — и бьюсь об заклад, что вы читаете ее, — из-за того, что C++ выбран в качестве языка разработки в очень многих крупных корпорациях, таких как Microsoft.

 

Коллоквиум

 

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

Контрольные вопросы

 

1. Какая разница между объектно-ориентированным и процедурным программированием?

2. Каковы этапы объектно-ориентированного анализа и проектирования?

3. Как связанны диаграммы последовательности и сотрудничества?

 

Упражнения

 

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

2. Какие объекты и какие классы потребуются для имитации этой ситуации?

3. Усложним ситуацию из упражнения 1. Предположим, что есть три вида водителей: таксисты, переезжающие переход на красный свет; иногородние, которые едут медленно и осторожно; и частники, которые ведут машины по-разному, в зависимости от представлений о своей " крутизне".

4. Также есть два вида пешеходов: местные, которые переходят улицу, где им заблагорассудится, и туристы, которые переходят улицу только на зеленый свет.

5. А кроме того, есть еще велосипедисты, которые ведут себя то как пешеходы, то как водители.

6. Как эти соображения изменят модель?

7. Вам заказали программу планирования времени конференций и встреч, а также бронирования мест в гостинице для визитеров компании и для участников конференций. Определите главные подсистемы.

8. Спроектируйте интерфейсы к классам той части программы, обсуждаемой в упражнении 3, которая относится к резервированию гостиничных номеров.

 

День 19-й. Шаблоны

 

У программистов, использующих язык C++, появился новый мощный инструмент — " параметризованные типы", или шаблоны. Шаблонами настолько удобно пользоваться, что стандартная библиотека шаблонов (Standard Template Library — STL) бьша принята в состав определений языка C++. Итак, сегодня вы узнаете:

• Что такое шаблоны и как их использовать

• Как создать класс шаблонов

• Как создаются шаблоны функций

• Что представляет собой стандартная библиотека шаблонов (STL) и как ею пользоваться

Что такое шаблоны

 

При подведении итогов за вторую неделю обучения вы узнали, как построить объект PartsList и как его использовать для создания объекта PartsCatalog. Если же вы хотите воспользоваться объектом PartsList, чтобы составить, например, список кошек, у вас возникнет проблема: объект PartsList знает только о запчастях.

Чтобы решить эту проблему, можно создать базовый класс List и произвести из него классы PartsList и CatsList. Затем можно вырезать и вставить существенную часть класса PartsList в объявление нового класса CatsList. А через неделю, когда вы захотите составить список объектов Car, вам придется опять создавать новый класс и снова " вырезать и вставлять".

Очевидно, что это неприемлемое решение. Ведь через какое-то время класс List и его производные классы придется расширять. А работа, которую пришлось бы проделать, чтобы убедиться в том, что все изменения, коснувшиеся базового класса, распространены и на все связанные классы, превратилась бы в настоящий кошмар.

Благодаря шаблонам, эта проблема легко решается, а с принятием стандарта ANSI шаблоны стали неотъемлемой частью языка C++, подобно которому они сохраняют тип и очень гибки.

 

Параметризованные типы

 

С помошью шаблонов можно " научить" компилятор составлять список элементов любого типа, а не только заданного: PartsList — это список частей, CatsList — это список кошек. Единственное отличие между ними — тип элементов списка. При использовании шаблонов тип элементов списка становится параметром для определения класса.

Обшим компонентом практически всех библиотек C++ является класс массивов. Как показано на примере с классом List, утомительно и крайне неэффективно создавать один класс массивов для целых, другой — для двойных слов, а еще один — для массива элементов типа Animals. Шаблоны позволяют объявить параметризованный класс массивов, а затем указать, какой тип объекта будет содержаться в каждом экземпляре массива. Заметьте, что стандартная библиотека шаблонов предоставляет стандартизированный набор контейнерных классов, включая массивы, списки и т.д. Сейчас мы выясняем, что нужно для создания вашего собственного класса, только для того, чтобы вы до конца поняли, как работают шаблоны; но в коммерческой программе вы почти стопроцентно будете использовать классы библиотеки STL, а не собственного изготовления.

Создание экземпляра шаблона

 

Экземпляризация (instantiation) — это операция создания определенного типа из шаблона. Отдельные классы называются экземплярами шаблона.

Параметризованные шаблоны (parameterized templates) предоставляют возможность создания общего класса и для построения конкретных экземпляров передают этому классу в качестве параметров типы данных.

 

 

Объявление шаблона

 

Объявляем параметризованный объект Array (шаблон для массива) путем записи следующих строк:

1: template < class T> // объявляем шаблон и параметр

2: class Array // параметризуемый класс

3: {

4: public:

5: Array();

6: // здесь должно быть полное определение класса

7: };

 

Ключевое слово template используется в начале каждого объявления и определения класса шаблона. Параметры шаблона располагаются за ключевым словом template. Параметры — это элементы, которые изменяются с каждым экземпляром. Например, в приведенном выше шаблоне массивов будет изменяться тип объектов, сохраняемых в массиве. Один экземпляр шаблона может хранить массив целых чисел, а другой — массив объектов класса Animals.

В этом примере используется ключевое слово class, за которым следует идентификатор Т. Это ключевое слово означает, что параметром является тип. Идентификатор T используется в остальной части определения шаблона, указывая тем самым на параметризованный тип. В одном экземпляре этого класса вместо идентификатора T повсюду будет стоять тип int, а в другом — тип Cat.

Чтобы объявить экземпляры параметризованного класса Array для типов int и Cat, следует написать:

Array< int> anIntArray;

Array< Cat> aCatArray;

Объект anIntArray представляет собой массив целых чисел, а объект aCatArray — массив элементов типа Cat. Теперь вы можете использовать тип Array< int> в любом месте, где обычно указывается какой-либо тип — для возвращаемого функцией значения, для параметра функции и т.д. В листинге 19.1 содержится полное объявление уже рассмотренного нами шаблона Array.

 

Примечание: Программа в листинге 19.1 не завершена!

 

Листинг 19.1. Шаблон класса Array

1: //Листинг 19.1. Шаблон класса массивов

2: #include < iostream.h>

3: const int DefaultSize = 10;

4:

5: template < class T> // объявляем шаблон и параметр

6: class Array // параметризуемый класс

7: {

8: public:

9: // конструкторы

10: Array(int itsSize = DefaultSize);

11: Array(const Array & rhs);

12: ~Array() { delete [] pType; }

13:

14: // операторы

15: Array& operator=(const Array& );

16: T& operator[](int offSet) { return pType[offSet]; }

17:

18: // методы доступа

19: int getSize() { return itsSize; }

20:

21: private:

22: T *pType;

23: int itsSize;

24: };

 

Результат:

Результатов нет. Эта программа не завершена.

 

Анализ: Определение шаблона начинается в строке 5 с ключевого слова template за которым следует параметр. В данном случае параметр идентифицируется как тип за счет использования ключевого слова class, а идентификатор T используется для представления параметризованного типа.

Со строки 6 и до конца определения шаблона (строка 24) вся остальная часть объявления аналогична любому другому объявлению класса. Единственное отличие заключается в том, что везде, где обычно должен стоять тип объекта, используется идентификатор T. Например, можно предположить, что operator[] должен возвращать ссылку на объект в массиве, а на самом деле он объявляется для возврата ссылки на идентификатор типа T.

Если объявлен экземпляр целочисленного массива, перегруженный оператор присваивания этого класса возвратит ссылку на тип integer. А при объявлении экземпляра массива Animal оператор присваивания возвратит ссылку на объект типа Animal.

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

 

Внутри объявления класса слово Array может использоваться без спецификаторов. В другом месте программы этот класс будет упоминаться как Array< T>. Например, если не поместить конструктор внутри объявления класса, то вы должны записать следующее:

template < class T>

Array< T>:: Array(int size):

itsSize = size

{

pType = new T[size];

for (int i = 0; i< size; i++)

pType[i] = 0;

}

 

Объявление, занимающее первую строку этого фрагмента кода, устанавливает в качестве параметра тип данных (class T). В таком случае в программе на шаблон можно ссылаться как Array< T>, а объявленную функцию-член вызывать строкой

Array(int size).

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

 

Выполнение шаблона

 

Для выполнения класса шаблона Array необходимо создать конструктор-копировщик, перегрузить оператор присваивания (operator=) и т.д. В листинге 19.2 показана простая консольная программа, предназначенная для выполнения этого шаблона.

 

Примечание: Некоторые более старые компиляторы не поддерживают использование шаблонов. Но шаблоны являются частью стандарта ANSI C++, поэтому компиляторы всех основных производителей поддерживают шаблоны в своих текущих версиях. Если у вас очень старый компилятор, вы не сможете компилировать и выполнять упражнения, приведенные в этой главе. Однако все же стоит прочитать ее до конца, а затем вернуться к этому материалу после модернизации своего компилятора.

 

Листинг 19.2. Использвание шаблона массива

1: #include < iostream.h>

2:

3: const int DefaultSize = 10;

4:

5: // обычный класс Animal для

6: // создания массива животных

7:

8: class Animal

9: {

10: public:

11: Animal(int);

12: Animal();

13: ~Animal() { }

14: int GetWeight() const { return itsWeight; }

15: void Display() const { cout < < itsWeight; }

16: private:

17: int itsWeight;

18: };

19:

20: Animal:: Animal(int weight):

21: itsWeight(weight)

22: { }

23:

24: Animal:: Animal():

25: itsWeight(0)

26: { }

27:

28:

29: template < class T> // обьявляем шаблон и параметр

30: class Array // параметризованный класс

31: {

32: public:

33: // конструкторы

34: Array(int itsSize - DefaultSize);

35: Array(const Array & rhs);

36: ~Array() { delete [] pType; }

37:

38: // операторы

39: Array& operator=(const Array& );

40: T& operator[](int offSet) { return pType[offSet]; }

41: const T& operator[](int offSet) const

42: { return pType[offSet]; }

43: // методы доступа

44: int GetSize() const { return itsSize; }

45:

46: private:

47: T *рТуре;

48: int itsSize;

49: };

50:

51: // выполнения...

52:

53: // выполняем конструктор

54: template < class T>

55: Array< T>:: Array(int size):

56: itsSize(size)

57: {

58: pType = new T[size];

59: for (int i = 0; i< size; i++)

60: pType[i] = 0;

61: }

62:

63: // конструктор-копировщик

64: template < class T>

65: Array< T>:: Array(const Array & rhs)

66: {

67: itsSize = rhs.GetSize();

68: pType = new T[itsSize];

69: for (int i = 0; i< itsSize; i++)

70: pType[i] = rhs[i];

71: }

72:

73: // оператор присваивания

74: template < class T>

75: Array< T> & Array< T>:: operator=(const Array & rhs)

76: {

77: if (this == & rhs)

78: return *this;

79: delete [] pType;

80: itsSize = rhs.GetSize();

81: pType = new T[itsSize];

82: for (int i = 0; i< itsSize: i++)

83: pType[i] = rhs[i];

84: return *this;

85: }

86:

87: // исполняемая программа

88: int main()

89: {

90: Array< int> theArray; // массив целых

91: Array< Animal> theZoo; // массив животных

92: Animal *pAnimal;

93:

94: // заполняем массивы

95: for (int i = 0; i < theArray.GetSize(); i++)

96: {

97: theArray[i] = i*2;

98: pAnimal = new Animal(i*3);

99: theZoo[i] = *pAnimal;

100: delete pAnimal;

101: }

102: // выводим на печать содержимое массивов

103: for (int j = 0; j < theArray.GetSize(); j++)

104: {

105: cout < < " theArray[" < < j < < " ]: \t";

106: cout < < theArray[j] < < " \t\t";

107: cout < < " theZoo[" < < j < < " ]: \t";

108: theZoo[j].Display();

109: cout < < endl;

110: }

111:

112: return 0;

113: }

 

Результат:

theArray[0] 0 theZoo[0] 0

theArray[1] 2 theZoo[1] 3

theArray[2] 4 theZoo[2] - 6

theArray[3] 6 theZoo[3] 9

theArray[4] 8 theZoo[4] 12

theArray[5] 10 theZoo[5] 15

theArray[6] 12 theZoo[6] 18

theArray[7] 14 theZoo[7] 21

theArray[8] 16 theZoo[8] 24

theArray[9] 18 theZoo[9] 27

 

Анализ: В строках 8-26 выполняется создание класса Animal, благодаря которому объекты определяемого пользователем типа можно будет добавлять в массив.

Содержимое строки 29 означает, что в следующих за ней строках объявляется шаблон, параметром для которого является тип, обозначенный идентификатором Т. Класс Array содержит два конструктора, причем первый конструктор принимает размер и по умолчанию устанавливает его равным значению целочисленной константы DefaultSize.

Затем объявляются операторы присваивания и индексирования, причем объявляются константная и не константная версии оператора индексирования. В качестве единственного метода доступа служит функция GetSize(), которая возвращает размер массива.

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

Раздел закрытых данных содержит переменные-члены размера массива и указатель на массив объектов, реально помещенных в память.

 

 

Функции шаблона

 

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

void SomeFunction(Array< int> & ); // правильно

А запись

void SomeFunction(Array< T> & ); // ошибка!

неверна, поскольку отсюда не ясно, что представляет собой выражение T&. Запись

void SomeFunction(Array & ); // ошибка!

тоже ошибочна, так как объекта класса Array не существует — есть только шаблон и его экземпляры.

Чтобы реализовать более общий подход использования объектов, созданных на основе шаблона, нужно объявить функцию шаблона:

template < class T>

void MyTemplateFunction(Array< T> & ); // верно

Здесь MyTemplateFunction() объявлена как функция шаблона, на что указывает первая строка объявления. Заметьте, что функции шаблонов, подобно другим функциям, могут иметь любые имена.

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

template < class T>

void MyOtherFunction(Array< T> &, Array< int> & ); // верно

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

 

Шаблоны и друзья

 

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

• дружественный класс или функция, не являющиеся шаблоном;

• дружественный шаблон класса или функция, входящая в шаблон;

• дружественный шаблон класса или шаблонная функция, специализированные по типу данных.


Поделиться:



Популярное:

  1. I.3. Кинокультура и культура слова: отношение противостояния
  2. II. Совершенствование навыков нападающего удара против блока—20 мин.
  3. IV. Санитарно - противоэпидемический режим в отделении.
  4. V. АПОГЕЙ ГРАЖДАНСКОЙ ВОЙНЫ. ИТОГИ СОЦИАЛЬНОГО ПРОТИВОСТОЯНИЯ
  5. Административные правонарушения в области охраны историко-культурного наследия. Правонарушения против порядка использования топливно-энергетических ресурсов (Гл. 19,20)
  6. Альфа-адреноблокаторы: классификация, основные показания и противопоказания, побочные эффекты
  7. Анализ состояния и перспективы развития средств воздушного нападения вероятного противника
  8. Англия, Франция и Турция против России
  9. Антагонистические и неантагонистические противоречия.
  10. Антиагреганты: классификация, основные показания и противопоказания, побочные эффекты
  11. Архетипические противопоставления в мифах
  12. Атомно-молекулярное взаимодействие поверхностей. Оценка химического, молекулярного и электростатического взаимодействия и сопротивления движению.


Последнее изменение этой страницы: 2017-03-08; Просмотров: 565; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.205 с.)
Главная | Случайная страница | Обратная связь