Сравнение возможности передачи аргументов по умолчанию с перегрузкой функций



 

Как упоминалось в начале этого раздела, одним из применений передачи аргументов по умолчанию является "сокращенная форма" перегрузки функций. Чтобы понять это, представьте, что вам нужно создать две "адаптированные" версии стандартной функции strcat() . Одна версия должна присоединять все содержимое одной строки к концу другой. Вторая же принимает третий аргумент, который задает количество конкатенируемых (присоединяемых) символов. Другими словами, эта версия должна конкатенировать только заданное количество символов одной строки к концу другой.

Допустим, что вы назвали свои функции именем mystrcat() и предложили такой вариант их прототипов.

 

 

Первая версия должна скопировать len символов из строки s2 в конец строки s1 . Вторая версия копирует всю строку, адресуемую указателем s2 , в конец строки, адресуемой указателем s1 , т.е. действует подобно стандартной функции strcat() .

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

 

 

Здесь функция mystrcat() присоединяет len символов строки, адресуемой параметром s2 , к концу строки, адресуемой параметром s1 . Но если значение len равно ‑1 , как и в случае разрешения передачи этого аргумента по умолчанию, функция mystrcat() присоединит к строке s1 всю строку, адресуемую параметром s2 . (Другими словами, если значение len равно ‑1 , функция mystrcat() действует подобно стандартной функции strcat() .) Используя для параметра len возможность передачи аргумента по умолчанию, обе операции можно объединить в одной функции.

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

 

Об использовании аргументов, передаваемых по умолчанию

 

Несмотря на то что аргументы, передаваемые функции по умолчанию, – очень мощное средство программирования (при их корректном использовании), с ними могут иногда возникать проблемы. Их назначение – позволить функции эффективно выполнять свою работу, обеспечивая при всей простоте этого механизма значительную гибкость. В этом смысле все передаваемые по умолчанию аргументы должны отражать способ наиболее общего использования функции или альтернативного ее применения. Если не существует некоторого единого значения, которое обычно присваивается тому или иному параметру, то и нет смысла объявлять соответствующий аргумент по умолчанию. На самом деле объявление аргументов, передаваемых функции по умолчанию, при недостаточном для этого основании деструктуризирует код, поскольку такие аргументы способны сбить с толку любого, кому придется разбираться в такой программе. Наконец, основным принципом использования аргументов по умолчанию должен быть, как у врачей, принцип "не навредить" . Другими словами, случайное использование аргумента по умолчанию не должно привести к необратимым отрицательным последствиям. Ведь такой аргумент можно просто забыть указать при вызове некоторой функции, и, если это случится, подобный промах не должен вызвать, например, потерю важных данных!

 

Перегрузка функций и неоднозначность

 

Неоднозначность возникает тогда, когда компилятор не может определить различие между двумя перегруженными функциями.

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

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

 

 

Как отмечено в комментарии, ошибки здесь нет, поскольку C++ автоматически преобразует символ 'c' в его double ‑эквивалент. Вообще говоря, в C++ запрещено довольно мало видов преобразований типов. Несмотря на то что автоматическое преобразование типов – это очень удобно, оно, тем не менее, является главной причиной неоднозначности. Рассмотрим следующую программу.

 

 

Здесь благодаря перегрузке функция myfunc() может принимать аргументы либо типа float , либо типа double . При выполнении строки кода

 

 

не возникает никакой неоднозначности: компилятор "уверенно" обеспечивает вызов функции myfunc(double) , поскольку, если не задано явным образом иное, все литералы с плавающей точкой в C++ автоматически получают тип double . Но при вызове функции myfunc() с аргументом, равным целому числу 10 , в программу вносится неоднозначность, поскольку компилятору неизвестно, в какой тип ему следует преобразовать этот аргумент: float или double . Оба преобразования допустимы. В такой неоднозначной ситуации будет выдано сообщение об ошибке, и программа не скомпилируется.

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

А вот еще один пример неоднозначности, вызванной автоматическим преобразованием типов в C++.

 

 

В C++ типы unsigned char и char не являются существенно неоднозначными. (Это – различные типы.) Но при вызове функции myfunc() с целочисленным аргументом 88 компилятор "не знает" , какую функцию ему выполнить, т.е. в значение какого типа ему следует преобразовать число 88: типа char  или типа unsigned char ? Оба преобразования здесь вполне допустимы.

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

 

 

Здесь в первом обращении к функции myfunc() задается два аргумента, поэтому у компилятора нет никаких сомнений в выборе нужной функции, а именно myfunc(int i, int j) , т.е. никакой неоднозначности в этом случае не привносится. Но при втором обращении к функции myfunc() мы получаем неоднозначность, поскольку компилятор "не знает" , то ли ему вызвать версию функции myfunc() , которая принимает один аргумент, то ли использовать возможность передачи аргумента по умолчанию к версии, которая принимает два аргумента.

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

 


Дата добавления: 2018-09-22; просмотров: 321; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!