Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Книга C++.doc
Скачиваний:
24
Добавлен:
10.11.2019
Размер:
2.48 Mб
Скачать

Преобразования, определяемые классом

Конструктор с одним аргументом автоматически является функцией преобразования из типа аргумента к типу конструируемого класса. Рассмотренный ранее строковый класс имел следующий конструктор:

string::string(const char* s)

{

len = strlen(s);

S = new char[len + 1];

strcpy(S, s);

}

Представленное выражение - автоматическое преобразование типа от char* к string. Оно доступно как явно, так и неявно. Явно оно используется или как операция преобразования, или в приведении, или в функциональной форме. Таким образом, возможны два рабочих варианта кода:

string s;

char str[] = "Hello\n";

s = (string)str; // Выполняет преобразование, а затем присвоение

и

s = str; // Неявный вызов преобразования

Данный код - преобразование из уже определенного типа к типу, определяемому пользователем. Однако возможна обратная ситуация: в примере со строкой может возникнуть необходимость в преобразовании из строки в char*. Это может быть выполнено с помощью определения специальной функции преобразования внутри класса string следующим образом:

operator char*() { return S; }

Общая форма записи такой функции-члена:

operator тип() { ... }

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

Пример строкового класса с перегруженными операторами

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

Для решения данной задачи воспользуемся материалами данного урока.

#include <string.h>

#include <iostream.h>

class string // Объявление строкового класса

{

private:

char* S; // Строка

int len; // Длина строки

public:

string(); // Конструктор по умолчанию

string(const char* s); // Перегруженный конструктор

string(const string& s); // Конструктор копирования

~string() { delete [] S; }// Деструктор

// Перегрузка бинарного оператора

// Первый параметр передается неявно с помощью указателя this

// Функция реализует сцепление строк

string operator+(const string&);

// Перегрузка бинарного оператора

// Первый параметр передается неявно с помощью указателя this

// Функция реализует корректное присваивание объектов друг другу

string& operator=(const string&);

// Перегрузка типа

// Функция реализует преобразование объекта класса к типу char*

operator char*() { return S; }

void Sort(string s[], int n); // Функция сортировки

int GetLen() { return len; } // Функция возвращает длину строки

};

string::string()

{

S = new char[81]; // Выделение памяти под 81 элемент

// строки для объекта по умолчанию

for(int i = 0; i < 81; i++)

S[i] = 0;

len = 80;

}

string::string(const char* s)

{

len = strlen(s);

S = new char[len + 1];

strcpy(S, s); // Инициализация строкой, переданной

// пользователем

}

string::string(const string& s)

{

len = s.len;

S = new char[len + 1]; // Безопасное копирование

strcpy(S, s.S);

}

void string::Sort(string s[], int n)

{ // Сортировка строк

bool flag = true;

string temp;

for(int j = 1; ; j++)

{

for(int i = 0; i < n - j; i++)

if(strcmp(s[i], s[i + 1]) > 0) // Происходит обращение к

{ // строкам напрямую, благодаря

// неявному вызову функции класса string

// operator char*()

temp = s[i]; // Вызов функции operator=(s[i])

s[i] = s[i + 1]; // Вызов функции operator=(s[i + 1])

s[i + 1] = temp; // Вызов функции operator=(temp)

flag = false;

}

if(flag)

break;

flag = true;

}

}

string string::operator+(const string &str)

{ // Функция сцепления строк

string s; // Создание временного объекта

delete [] s.S; // Удаление старой строки

s.len = len + str.len; // Вычисление новой длины строки

s.S = new char[s.len + 1]; // Выделение памяти под новую строку

strcpy(s.S, S); // Инициализация первой части строки

strcat(s.S, str.S); // Инициализация второй части строки

return s; // Возврат нового объекта

}

string& string::operator=(const string &str)

{ // Функция, реализующая безопасное присваивание

delete [] S; // Удаление старой строки

len = str.len; // Вычисление новой длины строки

S = new char[len + 1]; // Выделение памяти под новую строку

strcpy(S, str.S); // Инициализация строки

return *this; // Возврат ссылки на "самого себя"

// Благодаря этому возможно многократное

// присваивание объектов друг другу

// например, string a, b, c; a = b = c;

}

void main(void)

{

string a, b, c;

cout << "Input the first part of string:\t";

cin.getline(a, a.GetLen());

cout << "Input the second part of string:\t";

cin.getline(b, b.GetLen());

// Использывались неявные вызовы функций

// a.operator char*() и b.operator char*()

c = a + b + "\nThat's all !\n";

// Произошел вызов конструктора преобразования

// для строки "\nThat's all !\n"

cout << c; // Вывод результирующей строки

// Неявный вызов функции c.operator char*()

}