Г. Шилдт - Полный справочник по C++ (1109478), страница 62
Текст из файла (страница 62)
Правильное применение аргументов по умолчанию Аргументы по умолчанию представляют собой мощный механизм, который, однако, зачастую используется неверно. Основное предназначение аргументов по умолчанию — обеспечить простой, естественный и эффективный стиль программирования, сохранив высокую гибкость программ. Следовательно, аргументы по умолчанию следует применять для очень распространенных ситуаций, в которых вызываются функции. Если аргумент не имеет определенного значения, которое он принимает в большинстве ситуаций, то его значение по умолчанию не стоит предусматривать вообще. Если значение по умолчанию выбрано непродуманно, оно лишь запутывает код и может привести к различным недоразумениям.
Кроме того, значение аргумента по умолчанию не должно вызывать опасных последствий для программы. Иначе говоря, непредвиденное применение значения по умолчанию не должно приводить к краху программы. И Перегрузка функций и неоднозначность Можно создать ситуацию, в которой компилятор не сможет сделать выбор среди нескольких перегруженных функций.
Такие ситуации называются неоднозначными (ашЬ(яоооз). Они являются ошибками, и программы, содержащие их, не компилируются. Основной причиной неоднозначности в программах на языке С++ является автоматическое преобразование типов. Как известно, компилятор пытается автоматически преобразовать тип фактических параметров к типу формальных аргументов, ожидаемых функцией. Рассмотрим следующий фрагмент программы. | ьпс шухипс(с)оиЬ1е с)) г // соцс « шусцпс('с')г // Это не ошибка, преобразование допускается Как указано в комментариях, этот фрагмент не содержит синтаксической ошибки, поскольку символ с можно преобразовать в тип ооа)з1в. Набор запрегценных преобразований типов в языке С++ довольно мал.
И все же, несмотря на удобспю, которое обеспечивает автоматическое преобразование типов, оно часто порождает неоднозначные ситуации. Рассмотрим в качестве примера следующую программу. Ввпс1пйе <1овсхеаш> из1пд пашеврасе вхбг х1оас шухппс(х1оас 1)г с)оо)э1е шуйппс(с)ои)э1е 1); Глава (4. Перегрузка функций, конструкторы копирования в аргументы по умолчанию Яг 7 з ос ямз г. ( ) ( сонг <с аугиззс(10.1! « " "; // Однозначная ситуация, // вызывается функция // пухипсИоиЬ1е) соит « язухипс(10); // неоднозначность хееихп 0/ ) т1оас язухипс(т1оах 1) ( техихзз з.з ) з)оиЬ1е гаутипс ИоиЬ1е з.) геситп -1з В этом примере Функция азуяипс() перегружена, поскольку она может получать аргумент типа а1оае или аоиь1е. В однозначной ситуации Функция дзутипс(аоиь1е) вызывается без проблем, поскольку все аргументы типа а1оае автоматически преобразовываются в тип аоиь1е.
Это совершенно однозначное преобразование. В то же время вызов звуаипс <10) порождает неоднозначную ситуацию, поскольку компилятор не знает, а какой тип следует преобразовать целый аргумент — азова или аоиЬ1а. В таком случае на экране появится сообщение об ошибке, и компиляция будет прекращена. Как следует из этого примера, неоднозначность порождается вовсе не перегрузкой Функции муаида(). Ее причиной является конкретный вызов Функции взухипс(), в котором используется неопределенный тип аргумента.
Рассмотрим еще олин пример неоднозначной ситуации, порождаемой автоматическим преобразованием типов. ))Ьпс1иг)е <1овсхеадз> ивапд пвдзеврасе вхз)з спат дзухипс(ипвфппег) спаг сЫ снах дзутипс <спат сЫ з Ьгзх ваап ( ) соис « кубипс('с'); // пивов функции дзухипс(синг) соис « дзуьипс(88) « " "; // Неоднозначность геситп 0; снах ьзутипс(ипвадпес) синг сЫ тезигп сЬ-1; сиат дзутипс(ипат си) ( техитп сЬ+1; Часть П. Язык С++ В языке С++ типы ива1япеа епвт И еьзак сами по себе не порождают неоднолзачности. Однако, когда выполняется вызов во липе<ее), компилятор не знает. какой вариант функции вызывать. Иначе говоря, совершенно непонятно, в какой тип следует преобразовать аргумент — в ипайяпеа опав или спад. Неоднозначныс ситуации могут возникнуть также из-за аргументов перегруженных функции, заданных по умолчанию.
Изучим следующую программу. М< пс1ибе <1овсгеаш> ивьпд пвшеврасе всбз 1пс шуЕипс<зпе 1)з 1пс звугипс(1пе 1, 1пс б< 1)з 1пе швз.п() свис « шугиис(4, 5) « " "; // Однозначная ситуация ооис « шуеипо(10)з // Неоднозначная ситуация гееигп Оз ) ьпе шугипо(1пе з.) ( гееигп 1; ) 1пс шубипс(1пе 1, 1пе б) ( гееихп 1*бз ) Здесь в первом вызове функции шуеипеО заданы два аргумента. Слеловательно, никакой неоднозначности нет, и вызывается функция шуеипе<1пс 1, хпе з). Однако при втором вызове функции шухиас <) возникает неоднозначность, поскольку компилятор не знает, какой вариант вызывать: то ли версию с одним аргументом, то ли версию с двумя аргументами, второй из которых задан по умолчанию.
Некоторые виды перегруженных функций неоднозначны по своей природе, несмотря на то что, на первый взгляд, они выглядят абсолютно точными. Рассмотрим в качестве примера следующую программу. // В этой программе есть ошибка. Еапс1ибе <1оведевш> ивьпя пвшеврасе всбз чо10 1(зпс х); чоьб Е(ьпс ах)з // Ошибка 1пс шв1п() 1пс в=10з Е(в)з // Ошибка, какую версию 4зункцнн 1() следует вызывать? гесихп 0; ) Глава <4. Перегрузка функций, конструкторы копирования и аргументы по умолчанию З(У ъоас( Е(ьпс х) ( соцс « внутри Функции Г<ьпс)1п"г ) уоЫ Е(тпс ах) ( соцс « "внутри Функции й(апс а)тп Как указано в комментариях программы, две функции нельзя перегружать, если вся разница между ними заключается в том, что одна из них имеет параметр, передаваемый с помогцью ссылки, а вторая получает аргумент по значению.
В этой ситуации компилятор не сможет выбрать однозначный вариант. Следует помнить, что между передачей параметров по ссылке и по значению нет синтаксической разницы. Часть П. Язык С++ С персгрузкои функций тесно связан механизм перегрузки операторов. В языке С+у можно перегрузить большинство операторов, настроив их на конкретньш класс. Например, в классе, поддерживающем стек, оператор "+" можно перегрузить для заталкивания элементов в стек, а оператор "-" — для выталкивания элементов из него. Перегруженный оператор сохраняет свое первоначальное предназначение. Просто набор типов, к которым его можно применять, расширяется.
Перегрузка операторов — олпа из самых эффективных возможностей языка С+-л. Она позволяет полностью интегрировать новые классы в существующую программную среду. После перегрузки операции над объектами новых классов выглядят точно так же, как операции над перел1епными встроенных пшов Кроме того, перегрузке операторов лежит в основе системы ввода-вывода в языке С++ Перегрузка операторов осуществляется с помощью аператарнгях функции (арета(ог Гцпсйоп), которые определяют дсиствия персгруже)шых операторов применительно к соответствующему классу.
Операторные функции создаются с помощью ключевого слова ореквсок. Операторные функции могут быть как членами класса, так и обычными функциями. Олнако обычныс операторные функции. как правило. объявляют дружественными по отношению к классу, для которого они псрегружают оператор В каждом из этих случаев операторная функция объявляется по-разному. Следовательно, необходимо рассмотреть эти варианты отдельно.
1:3 Создание операторной функции-члена Операторная функция-член имеет следующий вид: | тип еазералцаечага значения иня няаееа:: срехаесгв (еттае-аргулчентае) ( / / Операции Обычно операторная функция возвращает объект класса, с которым она работает, однако тип возвращаемого значения может быть любым. Символ М заменяется перегружаемым оператором. Например, если в классе перегружается оператор деления "У", операторная функция-член называется ореквсокд При перегрузке унарного оператора список аргументов остается пустым. При перегрузке бинарного оператора список аргументов содержит один параметр. (Эти необычные правила мы разъясним позже.) Рассмотрим простой пример.