Читайте также:
|
|
При объявлении переменных и параметров функций в описании типа может быть указано ключевое слово const.
Объявление f(const char *s) означает, что символы, адресуемые указателем s, изменять нельзя.
Объявление f(char const *s) означает, что указатель s изменять нельзя.
Также можно сделать объявление: f(const char const *s), которое будет означать, что ни указатель, ни переменную изменять нельзя.
Если в программе объект объявлен с помощью модификатора const, то у него можно вызывать лишь те методы, которые объявлены с этим же модификатором:
Class TTextReader
{
public:
int ItemCount() const;
...
};
Наличие константных объектов порождает проблему – огромная избыточность программного кода. Заранее программист не знает, будет ли пользователь (другой программист) его класса создавать константные объекты. Вследствие того, что это не исключено, программист начинает записывать слово const в объявление всех методов, в которых его можно записать. Многие методы являются виртуальными или вызывают виртуальные методы. Случается так, что в производных классах виртуальные методы, вызванные константными методами, модифицируют поля объектов (это требуется по условию задачи). Это приводит к логической проблеме, которая решается либо за счет применения оператора const_cast к указателю this в производных классах, либо за счет объявления полей в производных классах с модификатором mutable (записывается при описании полей класса в том случае, если они должны модифицироваться константными методами).
mutable int m_RefCount;
Также решить проблему можно при помощи перегрузки метода класса без модификатора const:
classTTextReader
{
public:
int ItemCount() const;
int ItemCount();
int ItemCount() const volatile;
int ItemCount() volatile;
...
};
Варианты объявления:
volatile TTextReader r;
const volatile TTextReader r;
const TTextReader r;
TTextReader r;
Ключевое слово volatile запрещает кэшировать значение переменной. Если в программе происходит считывание значения переменной, объявленной с этим ключевым словом, то значение считывается из памяти, а не из регистров, а запись всегда производится в память, в которой размещается данная переменная. Если ключевое слово volatile не указано, то оптимизатор C++ имеет право выполнять
регистровые операции (оптимизации) при чтении и записи переменных, а также размещать их в регистрах.
Операторы приведения типа в языке C++: const_cast, reinterpret_cast, static_cast, dynamic_cast
Static_cast – безопасное преобразование, не содержит за собой инструкций процессора.
Существует четыре оператора преобразования типа в С++:
reinterpret_cast<тип>(переменная)
static_cast<тип>(переменная)
const_cast<тип>(переменная)
dynamic_cast<тип>(переменная)
reinterpret_cast позволяет отключить контроль типов данных на уровне компилятора, с помощью него любой указатель может быть интерпретирован, как любой другой указатель, а также любая память или переменная может быть интерпретирована иначе. В программах этот оператор преобразования типа использовать не следует, так как он нарушает переносимость программ. Его наличие свидетельствует о том, что программа не является кросс-платформенной. Обычно такое приведение типа применяется для низкоуровневого, зависящего от реализации программирования.
int i;
char* p;
p = reinterpret_cast<char *>(&i);
static_cast используется вместо преобразования тип(переменная), (тип)переменная и (тип)(переменная) при работе с классами, структурами и указателями на них. Он задуман по причине того, что в С++ выражение тип(переменная) может оказаться вызовом конструктора. Если в программе требуется преобразовать тип, а не вызвать конструктор типа, используется данный оператор. Кроме того, оператор (тип)переменная или (тип)(переменная) может в некоторых случаях оказаться преобразованием reinterpret_cast<тип>(переменная), а при разработке кросс-платформенных программ оператор reinterpret_cast всегда содержит потенциальную опасность неправильной работы программы на другой платформе. Поэтому вместо операторов тип(переменная), (тип)переменная и (тип)(переменная) следует использовать операторы reinterpret_cast и static_cast, которые убирают не явность из преобразования. Так как оператор static_cast является громоздким, то для простых типов данных допустимо использование форм: (тип)переменная и(тип)(переменная). Форма тип(переменная) не должна использоваться для преобразования типа. Static_cast допустима только в том случае, если _тип_ может быть неявно преобразовано в тип, который имеет выражение, или наоборот. В любом другом случае приведение типа вызывает ошибку.
Сonst_cast используется для приведения не константных указателей к константным и наоборот:
void f2(char* s);
void f1(const char* s)
{
...
f1(const char*s);
...
f2(const_cast<char>(s))
...
};
Операция const_cast предназначена исключительно для приведения типа, если значение имеет тип const или volatile.
const cast < имя_типа > (выражение)
Результатом такого приведения типа будет ошибка, если любые другие аспекты типов не совпадают. То есть имя_типа и выражение должны быть одного типа, за исключением того, что они могут отличаться только наличием или отсутствием const или volatile.
Операция const_cast не во всем хороша. Она может изменить указатель на величину, но эффект от изменения значения, заданного как const, не определен.
void change (const int * pt, int n);
int main ()
{
int pop l 38383;
const int рор2 = 2000;
change (& pop1, - 1);
change (& pop2, - 1);
void change (const int * pt, int n)
{
int * ре;
if (n < 0)
{
ре = const_ cast<int *> (pt);
*ре = 100;
}
}
Так как рор2 объявлен как const, компилятор может защитить его от изменения, как показано в следующем выводе программы:
рор1, рор2: 38383, 2000
рор1, рор2: 100, 2000
В данном случае компилятор создает временную копию рор2 и присваивает ее адрес ре, но, как уже
говорилось, в стандарте С++ данная ситуация называется неопределенной.
dynamic_cast соответствует оператору as в Delphi. Для работы этого оператора нужно в опциях компилятора включить опцию RTTI. Если это выполнено, то оператор dynamic_cast работает, как static_cast. Оператор dynamic_cast работает по-разному в зависимости от того, применяется он к ссылке на объект (&) или указателю на объект (*). Если оператор применяется к ссылке на объект, то преобразование не может быть выполнено и возникает исключительная ситуация. Если он применяется к указателю на объект и преобразование не может быть выполнено, оператор возвращает NULL.
17. Ссылки в языке C++. Рекомендации по работе со ссылками. Типичные ошибки при работе со ссылками.
Ссылки в языке C++
Ссылка является альтернативным именем объекта и объявляется следующим образом:
int i;
int &r = i;
Использование ссылки r эквивалентно использованию переменной i. Основное применение ссылок – передача параметров в функцию и возврат значения. В случае, когда ссылка используется в качестве параметра функции, она объявляется неинициализированной:
void f(int &i);
Во всех остальных случаях ссылка должна инициализироваться при объявлении, как показано ранее. Если ссылка является полем класса, она должна инициализироваться в конструкторе класса в списке инициализации до тела конструктора. При использовании в качестве параметров функций ссылки соответствуют var-параметрам в языке Delphi:
procedure P(var i: Integer);
Константные ссылки соответствуют const-параметрам в языке Delphi:
procedure P(const i: Integer);
При передаче ссылочного параметра в стек заносится адрес переменной, а не ее копия.
Cсылка во многом подобна указателю в замаскированной записи, где операция разыменования * предполагается неявно. И, фактически, это в какой-то степени именно то, чем является ссылка. Однако между ссылками и указателями существуют различия помимо обозначений. Одно из таких различий состоит в том, что ссылку необходимо инициализировать в момент ее объявления. Нельзя сначала объявить ссылку, а затем присвоить ей значение.
Ссылка во многом аналогична указателю со спецификатором const. Ее следует инициализировать в момент создания, после чего ссылка остается привязанной к определенной переменной до конца программы. Таким образом, конструкция
int & rodents = rats;
по сути, является замаскированной записью выражения, подобного следующему:
int const * pr = &rats;
В данном случае ссылка rodents играет ту же роль, что и выражение *pr.
{
int rats = 101;
int & rodents = rats; // rodents - это ссылка
int bunnies = 50;
rodents = bunnies;
}
Программа генерирует следующий вывод:
rats = 101, rodents = 101
адрес rats = Ox0065f d44, адрес rodents = Ox0065fd44
bunnies = 50, rats = 50, rodents = 50
адрес bunnies = Ox 0065fd48, адрес rodents = O0065f d4
Дата добавления: 2015-11-16; просмотров: 85 | Нарушение авторских прав
<== предыдущая страница | | | следующая страница ==> |
Понятие константного метода | | | Рекомендации по работе со ссылками |