15.6. Оператор "стрелка"
15.6. Оператор "стрелка"
Оператор "стрелка", разрешающий доступ к членам, может перегружаться для объектов класса. Он должен быть определен как функция-член и обеспечивать семантику указателя. Чаще всего этот оператор используется в классах, которые предоставляют "интеллектуальный указатель" (smart pointer), ведущий себя аналогично встроенным, но поддерживают и некоторую дополнительную функциональность.
Допустим, мы хотим определить тип класса для представления указателя на объект Screen (см. главу 13):
class ScreenPtr {
// ...
private:
Screen *ptr;
};
Определение ScreenPtr должно быть таким, чтобы объект этого класса гарантировано указывал на объект Screen: в отличие от встроенного указателя, он не может быть нулевым. Тогда приложение сможет пользоваться объектами типа ScreenPtr, не проверяя, указывают ли они на какой-нибудь объект Screen. Для этого нужно определить класс ScreenPtr с конструктором, но без конструктора по умолчанию (детально конструкторы рассматривались в разделе 14.2):
class ScreenPtr {
public:
ScreenPtr( const Screen &s ) : ptr( &s ) { }
// ...
};
В любом определении объекта класса ScreenPtr должен присутствовать инициализатор – объект класса Screen, на который будет ссылаться объект ScreenPtr:
ScreenPtr p1; // ошибка: у класса ScreenPtr нет конструктора по умолчанию
Screen myScreen( 4, 4 );
ScreenPtr ps( myScreen ); // правильно
Чтобы класс ScreenPtr вел себя как встроенный указатель, необходимо определить некоторые перегруженные операторы – разыменования (*) и “стрелку” для доступа к членам:
// перегруженные операторы для поддержки поведения указателя
class ScreenPtr {
public:
Screen& operator*() { return *ptr; }
Screen* operator-() { return ptr; }
// ...
};
Оператор доступа к членам унарный, поэтому параметры ему не передаются. При использовании в составе выражения его результат зависит только от типа левого операнда. Например, в инструкции point-action(); исследуется тип point. Если это указатель на некоторый тип класса, то применяется семантика встроенного оператора доступа к члену. Если же это объект или ссылка на объект, то проверяется, есть ли в этом классе перегруженный оператор доступа. Когда перегруженный оператор "стрелка" определен, он вызывается для объекта point, иначе инструкция неверна, поскольку для обращения к членам самого объекта (в том числе по ссылке) следует использовать оператор "точка". Перегруженный оператор "стрелка" должен возвращать либо указатель на тип класса, либо объект класса, в котором он определен. Если возвращается указатель, то к нему применяется семантика встроенного оператора "стрелка". В противном случае процесс продолжается рекурсивно, пока не будет получен указатель или определена ошибка. Например, так можно воспользоваться объектом ps класса ScreenPtr для доступа к членам Screen: ps-move( 2, 3 ); Поскольку слева от оператора "стрелка" находится объект типа ScreenPtr, то употребляется перегруженный оператор этого класса, который возвращает указатель на объект Screen. Затем к полученному значению применяется встроенный оператор "стрелка" для вызова функции-члена move(). Ниже приводится небольшая программа для тестирования класса ScreenPtr. Объект типа ScreenPtr используется точно так же, как любой объект типа Screen*: #include iostream #include string #include "Screen.h" void printScreen( const ScreenPtr &ps ) { cout && "Screen Object ( " && ps-&height() && ", " && ps-&width() && " ) "; for ( int ix = 1; ix &= ps-&height(); ++ix ) { for ( int iy = 1; iy &= ps-&width(); ++iy ) cout &&ps-&get( ix, iy ); cout && " "; } } int main() { Screen sobj( 2, 5 ); string init( "HelloWorld" ); ScreenPtr ps( sobj ); // Установить содержимое экрана string::size_type initpos = 0; for ( int ix = 1; ix &= ps-&height(); ++ix ) for ( int iy = 1; iy &= ps-&width(); ++iy ) { ps-&move( ix, iy ); ps-&set( init[ initpos++ ] ); } // Вывести содержимое экрана printScreen( ps ); return 0; }
Разумеется, подобные манипуляции с указателями на объекты классов не так эффективны, как работа со встроенными указателями. Поэтому интеллектуальный указатель должен предоставлять дополнительную функциональность, важную для приложения, чтобы оправдать сложность своего использования.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
R.6.4.1 Оператор if
R.6.4.1 Оператор if Выражение должно быть арифметического типа, или типа указателя, или типа класс, для которого существует однозначное преобразование в арифметический тип или тип указателя (§R.12.3).Вычисляется выражение, и если оно имеет отличный от нуля результат,
R.6.5.3 Оператор for
R.6.5.3 Оператор for Оператор for for ( оператор-иниц выражение-1 opt ; выражение-2 opt ) операторэквивалентен конструкцииоператор-иницwhile ( выражение-1 ) { оператор выражение-2 ;}за исключением того факта, что оператор continue в операторе for вызовет выполнение выражение-2 перед тем, как
Правило 52: Если вы написали оператор new с размещением, напишите и соответствующий оператор delete
Правило 52: Если вы написали оператор new с размещением, напишите и соответствующий оператор delete Операторы new и delete с размещением встречаются в C++ не слишком часто, поэтому в том, что вы с ними не знакомы, нет ничего страшного. Вспомните (правила 16 и 17), что когда вы пишете такое
Оператор if/else
Оператор if/else В отличие от C и C++, оператор if/else в C# может работать только с булевыми выражениями, а не с произвольными значениями -1, 0. Поэтому в операторах if/else обычно используются операции C#, показанные в табл. 3.6. чтобы получить буквальные булевы значения.Таблица 3.6.
Оператор for
Оператор for Ключевое слово: forОбщие замечания: Оператор for для управления циклическим процессом использует три выражения, разделенные символами "точка с запятой". Инициализирующее выражение выполняется один раз, до выполнения любого из операторов цикла. Если проверяемое
Оператор do while
Оператор do while Ключевые слова: do, whileОбщие замечания: Оператор do while создает цикл, который повторяется до тех пор, пока выражение, проверяющее условие, не станет ложным, или нулем. Оператор do while является циклом с постусловием; после прохождения цикла принимается решение,
1. Оператор Select – базовый оператор языка структурированных запросов
1. Оператор Select – базовый оператор языка структурированных запросов Центральное место в языке структурированных запросов SQL занимает оператор Select, с помощью которого реализуется самая востребованная операция при работе с базами данных – запросы.Оператор Select
15.8.2. Оператор размещения new() и оператор delete()
15.8.2. Оператор размещения new() и оператор delete() Оператор-член new() может быть перегружен при условии, что все объявления имеют разные списки параметров. Первый параметр должен иметь тип size_t:class Screen {public:void *operator new( size_t );void *operator new( size_t, Screen * );// ...};Остальные параметры
1.4.7 Оператор while
1.4.7 Оператор while Рассмотрим копирование строки, когда заданы указатель p на ее первый символ и указатель q на целевую строку. По соглашению строка оканчивается символом с целым значением 0.while (p != 0) (* *q = *p; // скопировать символ q = q+1; p = p+1; *) *q = 0; // завершающий символ 0 скопирован
1.4.8 Оператор for
1.4.8 Оператор for Рассмотрим копирование десяти элементов одного вектора в другой:for (int i=0; i«10; i++) q[i]=p[i];Это эквивалентно int i = 0; while (i«10) (* q[i] = p[i]; i++; *) но более удобочитаемо, поскольку вся информация, управляющая циклом, локализована. При применении операции ++ к целой
9.4 Оператор While
9.4 Оператор While Оператор while имеет видwhile ( выражение ) операторВыполнение подоператора повторяется, пока значение выржения остается ненулевым. Проверка выполняется перед каждым выполнением оператора. Выражение обрабатывается как в услоном операторе
3.3. Оператор &
3.3. Оператор & При выполнении задания в экранном режиме происходит "захват" терминала на весь этот период. Перевод задания в фоновый режим позволяет освободить терминал для других целей. Чтобы выполнить команду в фоновом режиме, укажите после нее оператор &:команда
6.1. Оператор &&
6.1. Оператор && Общий формат оператора && таков:команда1 && команда2Эта инструкция обрабатывается следующим образом: правый операнд интерпретируется только тогда, когда левый операнд равен TRUE. Иными словами, вторая команда выполняется в том случае, если первая