Модификатор const
Заметка 2012 года. Версии программ и описанные приёмы могли устареть.
Существует множество способов использования const в C++, которые могут здорово облегчить разработку, позволить создавать более безопасный и быстрый код. Однако практика показывает, что многие C++ программисты либо недооценивают пользу ключевого слова const в C++, либо просто плохо с ним знакомы.
На мой взгляд этот модификатор может быть очень и очень полезен при разработке программ, а потому стоит уделить ему немного времени.
Безусловно, статья в первую очередь ориентирована на новичков, но я надеюсь что она поможет освежить или уточнить знания тем кто давно сделал свой выбор в пользу C++
Давайте выясним как работает const в C++ и для чего может быть полезен.
Существует несколько способов использования const, начнем с простого и пойдем дальше.
Данные и константы
Создание переменной i типа int, значение которой нельзя изменить:
const int i = 2;
const int i(2);
int consts i = 2;
int consts i(2);Если объявленную одним из вышеперечисленных способов переменную i попробовать изменить (т.е. написать что-то вроде
i = 3;), программа не скомпилируется.
Использовать const таким образом можно вместо директивы препроцессора #define, для определения размерности массива и т.д.
Указатели
Использование const с указателями несколько сложнее, так приходится познакомиться с его новым свойством - этот модификатор может защищать как сам указатель, так и данные, на которые последний указывает.
Изменяемые (перенаправляемые) указатели на неизменяемые символы:
const char *buff = "b";
char const *buff = "b";После такого объявления можно изменить (перенаправить) указатель, но нельзя изменить данные, на которые он указывает:
buff = "a"; // ОК
buff = 'a'; // Не скомпилируется, и правильно сделаетНеизменяемый указатель на символы, которые можно изменить:
char * const buff;После такого объявления уже нельзя изменить (перенаправить) указатель, но можно поменять данные, на которые он указывает:
buff = "a"; // Не скомпилируется
buff = 'a'; // ОКИспользовать const таким образом можно для контроля за значением указателей и данных, на которые они указывают.
Ссылки
Ссылка, через которую нельзя поменять значение:
int a = 2;
const int &iBuff = a;
int const &iBuff = a;
int & const iBuff = a;В данном примере я намерянно установил значения, т.к. без этого объявленная ссылка не имеет смысла, ведь через нее нельзя менять значения.
const int &iBuff; // Редкая фигня. Если вы не понимаете почему так — стоит разобраться прежде, чем идти дальше.Параметры
Символы буфера не могут быть изменен внутри функции:
void SomeFunction(const char *buff); // или (char const *buff)
void SomeFunction(const char &buff); // или (char const &buff)Обратите внимание, что правило (для указателей) о расположении const слева или справа от знака * здесь также работает:
void SomeFunction(char & const buff); // Защита копии указателя. Бессмысленно.Такое использование модификатора очень полезно, оно позволяет защищать данные, передаваемые в качестве параметров, от изменения внутри функции.
Данные класса
static const позволяет инициализировать значения членов класса прямо в его объявлении:
class cClass
{
private:
static const int i = 2; // Инициализировали значение прямо в объявлении класса
public:
cClass() {};
~cClass() {};
int GetI() { return i; };
};Методы класса
Методы класса, если объявить их как const, будут считать константой
this. Это значит что они не смогут менять значения переменных класса.
class cClass
{
private:
int i;
public:
cClass(int a) {}
void Function() const
{
i = 5; // Не работает, т.к. this считается константой
}
};Вы можете создавать константные методы класса, чтобы уберечь переменные класса от изменения его методами, но имейте в виду что конструктор и деструктор нельзя сделать константными.
Перегрузка методов класса
Напишем класс с двумя одноименными методами, один из которых сделаем const:
class cClass
{
private:
int i;
public:
cClass(int a)
{
i = a;
cout << "Constructor makes x = " << i << endl;
}
void Function()
{
cout << "f() tell x = " << i << endl;
}
void Function() const
{
cout << "f() const tell x = " << i << endl;
}
};Теперь создадим 2 экземпляра класса — Class и Class2, при этом Class2 сделаем const:
int main()
{
cClass Class(3);
Class.Function();
cClass const Class2(3);
Class2.Function();
char gg[20];
scanf(gg, 20);
return 0;
}Запустив программу, посмотрим какой метод будет вызваться для каждого из них:
Constructor makes x = 3
f() tell x = 3
Constructor makes x = 3
f() const tell x = 3Очевидно что константный объект вызвал константный же метод, а наоборот - обычный объект вызвал обычным метод. Т.о. const можно использовать для перегрузки методов класса, необходимо только учитывать — при отсутствии не-const методов, по умолчанию будут использоваться const-методы.
Константный класс
Говоря "константный класс" подразумевают в первую очередь объявление вида:
const cClass Class;Созданный таким образом объект будет не в состоянии изменить состояние класса и сможет вызывать только свои константные методы. Также следует учесть, что при таком создании все данные класса будут считаться const, независимо от того, как они были объявлены.
Новые комментарии закрыты: заметка из архива.