Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
шпоры по ямп.docx
Скачиваний:
10
Добавлен:
01.04.2025
Размер:
161.76 Кб
Скачать

19.Преобразования объектов класса.

Преобразования (изменения типа) объектов класса выполняются конструкторами и преобразующими функциями.

Такие преобразования, называемые пользовательскими, часто неявно применяются в дополнение к стандартным преобразованиям. Например, функция, ожидающая параметр типа Х, может вызываться не только с параметром типа Х, но и с параметром типа Т, если существует преобразование из Т в Х. Кроме того, пользовательские преобразования применяются для приведения инициализаторов, параметров функций, возвращаемых функциями значений, операндов в выражениях, управляющих выражений, операторах цикла ивыбора и для явного приведения типов.

Пользовательские преобразования применяются только там, где они однозначны.

3.1. Преобразование посредством конструктора

Конструктор с одним параметром задаёт преобразование типа своего параметра к типу своего класса.

Конструктор с одним параметром не обязательно вызывается явно.

class X

{ private:

int x;

public:

X(int n);

...

};

X::X(int n) { x = n; }

X a = 1;

// Эквивалентно X a = X(1)

Однако неявное преобразование может быть нежелательно в некоторых случаях.

class Str

{ private:

char *str;

public:

Str(int n) { str = new char [n]; *str = 0; }

Str(const char *p) { str = new char [strlen(p) + 1]; strcpy(str, p); }

~Str() { if (str) delete [] str; }

};

Str s = 'a';

// Создание строки из int('a') элементов

Неявное преобразование можно подавить, объявив конструктор с модификатором explicit. Такой конструктор будет вызваться только явно.

class Str

{ private:

char *str;

public:

explicit Str(int n) { str = new char [n]; *str = 0; }

Str(const char *p) { str = new char [strlen(p) + 1]; strcpy(str, p); }

~Str() { if (str) delete [] str; }

};

Str s1 = 'a';

Str s2(10);

// Ошибка – нет неявного преобразования char в Str

// Правильно – создаётся строка из 10 символов

3.2. Преобразующие функции

Функция-член класса Х, имя которой имеет вид operator <имя типа>, определяет преобразование из Х в тип, заданный именем типа. Такие функции называются преобразующими функциями или функциями приведения. Для такой функции не могут быть заданы ни параметры, ни возвращаемый тип.

class X

{ private:

int x;

public:

X(int n);

operator int();

...

};

X::X(int n) { x = n; }

X::operator int() { return x; }

int a;

X b(0);

a = (int)b;

// Явный вызов преобразующей функции

a = b;

// Неявный вызов преобразующей функции

3.3. Разрешение неоднозначности

Присваивание значения типа V объекту класса X допустимо в том случае, если имеется оператор присваивания X::operator= (Z) такой, что V является Z или существует единственное преобразование V в Z. Инициализация рассматривается аналогично.

В некоторых случаях значение требуемого типа может быть создано при помощи повторного использования конструкторов или операторов преобразования. Это должно осуществляться при помощи явных преобразований – допустим только один уровень неявных преобразований, определяемых пользователем. В некоторых случаях значение требуемого типа может быть создано более чем одним способом – такое недопустимо.

class X { ... X(int); X(char*); ... };

class Y { ... Y(int); ... };

class Z { ... Z(X); ... };

X f(X);

Y f(Y);

Z g(Z);

void main()

{ f(1);

f(X(1));

f(Y(1));

g("Mask");

g(X("Mask"));

g(Z("Mask"));

}

// Неоднозначность - f(X(1)) или f(Y(1))?

// Правильно

// Правильно

// Ошибка – требуется применение двух преобр., определённых пользователем

// Правильно – g(Z(X("Mask")))

// Правильно – g(Z(X("Mask")))

class XX { XX(int); };

void h(double);

void h(XX);

void main()

{ h(1); }

// h(double(1)) или h(XX(1))? Вызов h(1) означает h(double(1)),

// потому что в этом случае используются только стандартные преобразования.

Правила преобразования не являются ни самыми простыми для реализации из всех возможных, ни самыми легкими для документирования, ни настолько общими, как можно себе представить. Однако они довольно безопасны, и их применение не приводит к неприятным сюрпризам. Гораздо легче вручную разрешить неоднозначности, чем найти ошибку, вызванную преобразованием, о котором и не подозревали.