C++. Бархатный путь. Часть 2 - Операторная функция operator() с несколькими параметрами

ОГЛАВЛЕНИЕ

 

Операторная функция operator() с несколькими параметрами

И это ещё не всё! Ещё не рассматривались варианты операторной функции operator() с несколькими параметрами. И здесь следует вспомнить о функциях с переменным количеством параметров. Это не единственный, но наиболее оптимальный подход к объявлению операторной функции operator() с несколькими параметрами. Здесь мы не будем вдаваться в детали алгоритма извлечения информации из списка параметров (мы их уже обсуждали раньше), а ограничимся лишь общей схемой объявления и вариантами выражения вызова. В нашей версии (всего лишь одной из возможных!), первым параметром функции всегда будет целое число:

ComplexType& operator () (int, ...);// Прототип. ::::: ComplexType& ComplexType::operator () (int iKey, ...) { cout << "This is operator ( " << iKey << ", ...)" << endl; return *this; } ::::: CDw2(50); CDw2(50, 100); CDw2(50, "Это тоже вызов операторной функции", 3.14, 0,123456789);

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

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

Как известно, операция косвенного обращения -> является бинарной операцией. Её первым операндом является указатель на объект, вторым - имя члена класса.

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

Рассмотрим различные варианты объявления, определения и вызова этой операторной функции.

Первый вариант тривиален:

::::: ComplexType* operator -> (); ::::: ComplexType* ComplexType::operator -> () { cout << "This is operator -> ()..." << endl; return this; } :::::

Таково, в общих чертах, объявление и определение функции. Функция без параметров.

::::: if (CDw2.operator->() == NULL) cout << "!!!" << endl; :::::

Это полная форма вызова в выражении равенства в составе условного оператора.

::::: CDw3->real = 125.07; (CDw3.operator->())->real = 125.07; :::::

Сокращённая и полная формы вызова операторной функции в составе оператора присвоения. Функция возвращает адрес, к которому применяется обычная двухместная операция косвенного обращения.

А вот более простого варианта сокращённой формы вызова функции operator->(), наподобие того, который ранее использовался в составе условного оператора, в C++ не существует. Правильно построенных выражений вида (xObject->) с единственным операндом, где -> является символом операции, в C++ нет, поскольку -> бинарная операция.

Из-за того, что не всегда удаётся различить по контексту выражение вызова функции и операцию косвенного обращения, сокращённый вызов операторной функции operator->() используется исключительно для имитации выражений с операцией косвенного обращения.

Операторная функция operator->() возвращает указатель на объект, и как любая нестатическая функция-член класса должна вызываться непосредственно "из объекта". Эта прописная истина не представляла бы никакого интереса, если бы в C++ существовали жёсткие ограничения на тип возвращаемого значения функции-члена класса. Но таких ограничений для операторных функций в C++ не существует, а потому возможны и такие экзотические варианты операторных функций:

::::: class ComplexType { ::::: }; ::::: class rrr // Объявляется новый класс. { public: ComplexType* pComplexVal; // Собственные версии конструкторов и деструкторов. rrr () { pComplexVal = new ComplexType; // Порождение собственного экземпляра объекта ComplexType. } ~rrr () { if (pComplexVal) = delete pComplexVal; } // Наконец, встроенная операторная функция. ComplexType* operator -> () { cout << "This is operator -> ()..." << endl; return pComplexVal; } }; ::::: // А это уже собственно фрагмент программы… rrr rrrVal; // Определяем объект - представитель класса rrr. cout << rrrVal ->real << " real." << endl; ::::: Сокращённая форма вызова операторной функции operator->() имеет вид rrrVal->real и интерпретируется транслятором как (rrrVal.operator->())->real, о чём и свидетельствует оператор, содержащий полную форму вызова этой операторной функции. ::::: cout << (rrrVal.operator->())->imag << " imag." << endl; :::::

В этом случае из объекта-представителя класса rrr вызывается операторная функция, в обязательном порядке возвращающая адрес объекта-представителя класса ComplexType, к которому сразу же (!) применяется операция косвенного обращения.

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

Во-первых, описанные в этом разделе способы объявления и определения этих функций не имеет альтернативы.

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