Выбрать главу

* разрешается двумя шагами: Вызывается конвертер класса SmallInt, который возвращает целое число 3.

* Целое число 3 расширяется до 3.0 и складывается с константой двойной точности 3.14159, что дает 6.14159.

Такое поведение больше соответствует поведению операндов встроенных типов по сравнению с определенными ранее перегруженными операторами. Когда значение типа int складывается со значением типа double, то выполняется сложение двух чисел типа double (поскольку тип int расширяется до double) и результатом будет число того же типа.

В этой программе иллюстрируется применение класса SmallInt:

#include iostream

#include "SmallInt.h"

int main() {

cout "Введите SmallInt, пожалуйста: ";

while ( cin si1 ) {

cout "Прочитано значение "

si1 "\nОно ";

// SmallInt::operator int() вызывается дважды

cout ( ( si1 127 )

? "больше, чем "

: ( ( si1 127 )

? "меньше, чем "

: "равно ") ) "127\n";

cout "\Введите SmallInt, пожалуйста \

(ctrl-d для выхода): ";

}

cout "До встречи\n";

}

Откомпилированная программа выдает следующие результаты:

Введите SmallInt, пожалуйста: 127

Прочитано значение 127

Оно равно 127

Введите SmallInt, пожалуйста (ctrl-d для выхода): 126

Оно меньше, чем 127

Введите SmallInt, пожалуйста (ctrl-d для выхода): 128

Оно больше, чем 127

Введите SmallInt, пожалуйста (ctrl-d для выхода): 256

*** Ошибка диапазона SmallInt: 256 ***

В реализацию класса SmallInt добавили поддержку новой функциональности:

#include iostream

class SmallInt {

friend istream&

operator( istream &is, SmallInt &s );

friend ostream&

operator( ostream &is, const SmallInt &s )

{ return os s.value; }

public:

SmallInt( int i=0 ) : value( rangeCheck( i ) ){}

int operator=( int i )

{ return( value = rangeCheck( i ) ); }

operator int() { return value; }

private:

int rangeCheck( int );

int value;

};

Ниже приведены определения функций-членов, находящиеся вне тела класса:

istream& operator&&( istream &is, SmallInt &si ) {

int ix;

is ix;

si = ix; // SmallInt::operator=(int)

return is;

}

int SmallInt::rangeCheck( int i )

{

/* если установлен хотя бы один бит, кроме первых восьми,

* то значение слишком велико; сообщить и сразу выйти */

if ( i & ~0377 ) {

cerr "\n*** Ошибка диапазона SmallInt: "

i " ***" endl;

exit( -1 );

}

return i;

}

15.9.1. Конвертеры

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

Имя, находящееся за ключевым словом, не обязательно должно быть именем одного из встроенных типов. В показанном ниже классе Token определено несколько конвертеров. В одном из них для задания имени типа используется typedef tName, а в другом – тип класса SmallInt.

#include "SmallInt.h"

typedef char *tName;

class Token {

public:

Token( char *, int );

operator SmallInt() { return val; }

operator tName() { return name; }

operator int() { return val; }

// другие открытые члены

private:

SmallInt val;

char *name;

};

Обратите внимание, что определения конвертеров в типы SmallInt и int одинаковы. Конвертер Token::operator int() возвращает значение члена val. Поскольку val имеет тип SmallInt, то неявно применяется SmallInt::operator int() для преобразования val в тип int. Сам Token::operator int() неявно употребляется компилятором для преобразования объекта типа Token в значение типа int. Например, этот конвертер используется для неявного приведения фактических аргументов t1 и t2 типа Token к типу int формального параметра функции print():

#include "Token.h"

void print( int i )

{

cout "print( int ) : " i endl;

}

Token t1( "integer constant", 127 );

Token t2( "friend", 255 );

int main()

{

print( t1 ); // t1.operator int()

print( t2 ); // t2.operator int()

return 0;

}

После компиляции и запуска программа выведет такие строки:

print( int ) : 127

print( int ) : 255

Общий вид конвертера следующий:

operator type();

где type может быть встроенным типом, типом класса или именем typedef. Конвертеры, в которых type – тип массива или функции, не допускаются. Конвертер должен быть функцией-членом. В его объявлении не должны задаваться ни тип возвращаемого значения, ни список параметров: