Здесь в первом обращении к функции myfunc() задается два аргумента, поэтому у компилятора нет никаких сомнений в выборе нужной функции, а именно myfunc(int i, int j), т.е. никакой неоднозначности в этом случае не привносится. Но при втором обращении к функции myfunc() мы получаем неоднозначность, поскольку компилятор "не знает", то ли ему вызвать версию функции myfunc(), которая принимает один аргумент, то ли использовать возможность передачи аргумента по умолчанию к версии, которая принимает два аргумента.
Программируя на языке C++, вам еще не раз придется столкнуться с ошибками неоднозначности, которые, к сожалению, очень легко "проникают" в программы, и только опыт и практика помогут вам избавиться от них.
Глава 9: Еще о типах данных и операторах
Прежде чем переходить к более сложным средствам C++, имеет смысл подробнее познакомиться с некоторыми типами данных и операторами. Кроме уже рассмотренных нами типов данных, в C++ определены и другие. Одни из них состоят из модификаторов, добавляемых к уже известным вам типам. Другие включают перечисления, а третьи используют ключевое слово typedef. C++ также поддерживает ряд операторов, которые значительно расширяют область действия языка и позволяют решать задачи программирования в весьма широком диапазоне. Речь идет о поразрядных операторах, операторах сдвига, а также операторах "?" и sizeof. Кроме того, в этой главе рассматриваются такие специальные операторы, как new и delete. Они предназначены для поддержки С++-системы динамического распределения памяти.
Спецификаторы типа const и volatile Спецификаторы типа const и volatile управляют доступом к переменной.
В C++ определено два спецификатора типа, которые оказывают влияние на то, каким образом можно получить доступ к переменным или модифицировать их. Это спецификаторы const и volatile. Официально они именуются cv-спецификаторами и должны предшествовать базовому типу при объявлении переменной.
Спецификатор типа const Переменные, объявленные с использованием спецификатора const, не могут изменить свои значения во время выполнения программы. Однако любой const-переменной можно присвоить некоторое начальное значение. Например, при выполнении инструкции
const double version = 3.2;
создается double-переменная version, которая содержит значение 3.2, и это значение программа изменить уже не может. Но эту переменную можно использовать в других выражениях. Любая const-переменная получает значение либо во время явно задаваемой инициализации, либо при использовании аппаратно-зависимых средств. Применение спецификатора const к объявлению переменной гарантирует, что она не будет модифицирована другими частями вашей программы.
Спецификатор const предотвращает модификацию переменной при выполнении программы.
Спецификатор const имеет ряд важных применений. Возможно, чаще всего его используют для создания const-параметров типа указатель. Такой параметр-указатель защищает объект, на который он ссылается, от модификации со стороны функции. Другими словами, если параметр-указатель предваряется ключевым словом const, никакая инструкция этой функции не может модифицировать переменную, адресуемую этим параметром. Например, функция code() в следующей короткой программе сдвигает каждую букву в сообщении на одну алфавитную позицию (т.е. вместо буквы 'А' ставится буква 'Б' и т.д.), отображая таким образом сообщение в закодированном виде. Использование спецификатора const в объявлении параметра не позволяет коду функции модифицировать объект, на который указывает этот параметр.
#include
using namespace std;
void code(const char *str);
int main()
{
code("Это тест.");
return 0;
}
/* Использование спецификатора const гарантирует, что str не может изменить аргумент, на который он указывает.
*/
void code(const char *str)
{
while(*str) {
cout << (char) (*str+1);
str++;
}
}
Поскольку параметр str объявляется как const-указатель, у функции code() нет никакой возможности внести изменения в строку, адресуемую параметром str. Но если вы попытаетесь написать функцию code() так, как показано в следующем примере, то обязательно получите сообщение об ошибке, и программа не скомпилируется.
// Этот код неверен.
void code(const char *str)
{
while(*str) {
*str = *str + 1; // Ошибка, аргумент модифицировать нельзя.