есть ли объект суммой его частей? Имеет ли суть классы деталей автомобиля, такие Руль, Колеса и Двери, создавать от общего класса Автомобиль, как продемонстрировано на рис. 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++ выбран в качестве языка разработки в весьма многих больших корпорациях, таких как Микрософт.
Коллоквиум
В этом разделе предлагаются вопросы для укрепления и самоконтроля взятых знаний, и последовательность упражнений, каковые окажут помощь закрепить ваши практические навыки. Постарайтесь самостоятельно ответить на вопросы теста и выполнить задания, а позже сверьте полученные результаты с ответами в приложении Г. Не приступайте к изучению материала следующей главы, в случае, если для вас остались неясными хотя бы кое-какие из предложенных ниже вопросов.
Контрольные вопросы
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 // объявляем параметр и шаблон
2: class Array // параметризуемый класс
3: {
4: public:
5: Array();
6: // тут должно быть полное определение класса
7: };
Главное слово template употребляется в начале определения класса и каждого объявления шаблона. Параметры шаблона находятся за главным словом template. Параметры — это элементы, каковые изменяются с каждым экземпляром. К примеру, в приведенном выше шаблоне массивов будет изменяться тип объектов, сохраняемых в массиве. Один экземпляр шаблона может хранить массив целых чисел, а второй — массив объектов класса Animals.
В этом примере употребляется главное слово class, за которым направляться идентификатор Т. Это главное слово свидетельствует, что параметром есть тип. Идентификатор T употребляется в другой части определения шаблона, показывая тем самым на параметризованный тип. В одном экземпляре этого класса вместо идентификатора T везде будет находиться тип int, а в другом — тип Cat.
Дабы заявить экземпляры параметризованного класса Array для типов int и Cat, направляться написать:
Array anIntArray;
Array aCatArray;
Объект anIntArray является массивом целых чисел, а объект aCatArray — массив элементов типа Cat. Сейчас вы имеете возможность применять тип Array в любом месте, где в большинстве случаев указывается какой-либо тип — для возвращаемого функцией значения, для параметра функции и т.д. В листинге 19.1 содержится полное объявление уже рассмотренного нами шаблона Array.
Примечание: Программа в листинге 19.1 не закончена!
Листинг 19.1. Шаблон класса Array
1: //Листинг 19.1. Шаблон класса массивов
2: #include
3: const int DefaultSize = 10;
4:
5: template // объявляем параметр и шаблон
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. К примеру, если не поместить конструктор в объявления класса, то вы должны записать следующее:
template
Array::Array(int size):
itsSize = size
{
pType = new T[size];
for (int i = 0; i
pType[i] = 0;
}
Объявление, занимающее первую строчок этого фрагмента кода, устанавливает в качестве параметра тип данных (class T). При таких условиях в программе на шаблон возможно ссылаться как Array, а заявленную функцию-член вызывать строчком
Array(int size).
Другая часть функции имеет такой же вид, какой мог быть у каждый функции. Это простой и предпочтительный способ его функций и создания класса методом несложного объявления до включения в шаблон.
Исполнение шаблона
Для исполнения класса шаблона Array нужно создать конструктор-копировщик, перегрузить оператор присваивания (operator=) и т.д. В листинге 19.2 продемонстрирована несложная консольная программа, предназначенная для исполнения этого шаблона.
Примечание: Кое-какие более ветхие компиляторы не поддерживают применение шаблонов. Но шаблоны являются частью стандарта ANSI C++, исходя из этого компиляторы всех главных производителей поддерживают шаблоны в собственных текущих предположениях. В случае, если у вас весьма ветхий компилятор, вы не сможете компилировать и делать упражнения, приведенные в данной главе. Но все же стоит прочесть ее до конца, а после этого возвратиться к этому материалу по окончании модернизации собственного компилятора.
Листинг 19.2. Использвание шаблона массива
1: #include
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
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 // обьявляем параметр и шаблон
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
55: Array::Array(int size):
56: itsSize(size)
57: {
58: pType = new T[size];
59: for (int i = 0; i
60: pType[i] = 0;
61: }
62:
63: // конструктор-копировщик
64: template
65: Array::Array(const Array rhs)
66: {
67: itsSize = rhs.GetSize();
68: pType = new T[itsSize];
69: for (int i = 0; i
70: pType[i] = rhs[i];
71: }
72:
73: // оператор присваивания
74: template
75: Array Array::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
83: pType[i] = rhs[i];
84: return *this;
85: }
86:
87: // исполняемая программа
88: int main()
89: {
90: Array theArray; // массив целых
91: Array 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
106: cout
107: cout
108: theZoo[j].Display();
109: cout
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
Анализ: В строчках 8-26 выполняется создание класса Animal, благодаря которому объекты определяемого пользователем типа возможно будет додавать в массив.
Содержимое строчка 29 свидетельствует, что в следующих за ней строчках объявляется шаблон, параметром для которого есть тип, обозначенный идентификатором Т. Класс Array содержит два конструктора, причем первый конструктор принимает размер и по умолчанию устанавливает его равным значению целочисленной константы DefaultSize.
После этого объявляются операторы индексирования и присваивания, причем объявляются константная и не константная версии оператора индексирования. В качестве единственного способа доступа помогает функция GetSize(), которая возвращает размер массива.
Возможно, само собой разумеется, представить себе и более полный интерфейс. Так как для любой важной программы создания массива представленный тут вариант будет недостаточным. Как минимум, было нужно бы добавить операторы, предназначенные для удаления элементов, для упаковки и распаковки массива и т.д. Все это предусмотрено классами контейнеров библиотеки STL, но к этому мы возвратимся в конце занятия.
Раздел закрытых данных содержит указатель-и размера переменные члены массива на массив объектов, реально помещенных в память.
Функции шаблона
Если вы желаете передать функции объект массива, необходимо передавать конкретный экземпляр массива, а не шаблон. Исходя из этого, в случае, если некая функция SomeFunction() принимает в качестве параметра целочисленный массив, применяйте следующую запись:
void SomeFunction(Array); // верно
А запись
void SomeFunction(Array); // неточность!
неверна, потому, что из этого не ясно, что является выражением T. Запись
void SomeFunction(Array ); // неточность!
также ошибочна, поскольку объекта класса Array не существует — имеется лишь его экземпляры и шаблон.
Дабы реализовать более неспециализированный подход применения объектов, созданных на базе шаблона, необходимо заявить функцию шаблона:
template
void MyTemplateFunction(Array); // правильно
Тут MyTemplateFunction() заявлена как функция шаблона, на что показывает первая строчок объявления. Увидьте, что функции шаблонов, подобно другим функциям, смогут иметь каждые имена.
Функции шаблонов, кроме объектов, заданных в параметризованной форме, смогут кроме этого принимать и экземпляры шаблона. Проиллюстрируем это на примере:
template
void MyOtherFunction(Array, Array); // правильно
Обратите внимание на то, что эта функция принимает два массива: параметризованный массив и массив целых чисел. Первый возможно массивом любых объектов, а второй — лишь массивом целых чисел.
друзья и Шаблоны
В шаблонах классов смогут быть заявлены три типа друзей:
• дружественный класс либо функция, не являющиеся шаблоном;
• дружественный шаблон класса либо функция, входящая в шаблон;
• дружественный шаблон класса либо шаблонная функция, специальные по типу данных.