C++ Программирование в среде С++ Builder 5

Ниже мы приводим два примера


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

Листинг 8.2. Перегрузка операции сложения


//////////////////////////////////////////////////////
// StrAdd.cpp: Демонстрация перегрузки сложения для строк.
//
#pragma hdrstop
#include <condefs.h>
#include <string.h>
#include <stdio.h>
class String {


char *str; // Указатель на динамическую строку.
int len; // Длина строки.
String(int); // Вспомогательный конструктор. public:
String(const Strings); // Конструктор копии.
String(const char*); // Конструктор преобразования.
~String () ;
String Soperator=(const Strings);
String operators- (const Strings);
friend String operator+(const Strings, const Strings);
void Show () ;
};
String::String(int size)
{
len = size;
str = new char[len + 1]; // +1 байт для завершающего 0.
}
String::String(const String ssrc)
{
len = src.len;
str = new char[len + 1];
strcpy(str, src.str);
}
String::String(const char *s)
{
len = strlen(s) ;
str = new char[len + 1];
strcpy(str, s);
String::~String()
{
delete [] str;
///////////////////////////////////////////////////
// Операция присваивания.
//
String SString::operator=(const String &op)
{
delete [] str; // Удаление старых данных.
len = op.len;
str = new char[len + 1]; // Выделение новой строки.
strcpy(str, op.str);
return *this;
}
///////////////////////////////////////////////////
// Функция-элемент operator+0.
//
String String::operators- (const String &op)
{
String temp(len + op.len); // Временный объект.
strcpy(temp.str, str); // Копирование первой строки.
strcat(temp.str, op.str); // Присоединение второй строки.
return temp;
}
///////////////////////////////////////////////////
// Дружественная функция operator+() Аналогична предыдущей,
// но допускает С-строку в качестве первого операнда.


//
String operator+( const String Sfop, const String &sop)
{
String temp(fop.len + sop.len);
strcpy(temp.str, fop.str);
strcat(temp.str, sop.str);
return temp;
}
void String::Show()
{
printf("%s: %d \n", str, len);
}
irit main()
{
char cStr[] °= "This is а С string! ";
String rirst = "First String string. ;
String second = "Second String string. ";
String resStr = "";
resStr.Show() ;
resStr = first + second; // Вызывает операцию класса.
resStr.:Shp,w ();
resStr = cStr + resStr; // Вызывает дружественную
// операцию reeStr.Show()
resStr = first + second + cStr; // Обе операции - из
// класса. resStr.Show () ;
return 0;
}
На рис. 8.2 показан вывод программы. Пример позволяет пояснить, почему перегруженные функции операций часто делают друзьями, а не элементами класса. Это делается для того, чтобы передать функции первый операнд в параметре, а не как объект *this. В одном из операторов функции main () из примера первый операнд сложения — С-строка. Но это не объект класса, и компилятор никак не может вызвать String: :operator+ (Strings) . Однако есть дружественная функция operator+ (Strings, Strings). Поскольку имеется конструктор преобразования char* в String, компилятор автоматически приводит первый операнд к типу String, создавая на стеке временный объект, и затем выполняет сложение с помощью дружественной функции. Это аналог “возведения типа”, происходящего в арифметических выражениях.
На самом деле функция-элемент operator+ (Strings) здесь является излишней. Можно было бы'обойтись одной дружественной функцией сложения.

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



Рис. 8.2 Программа StrAdd

Листинг 8.3. Перегрузка операции индексации

////////////////////////////////////////////////////////////
// Index.срр: Строка в качестве индекса.
//
#pragma hdrstop
#include <condefs.h>
#include <stdio.h>
#include <string.h>
const int Maxltems = 16;
class AArr {
int nitems;
char * keys[Maxltems];
char *items[Maxltems];
static const char error [];
public:
AArr() { nitems =0; }
~AArr();
void Addltem(const char*, const char*);
const char ^operator[](const char*);
};
consk char AArr::error[] = "*** Not found. ***";
////////////////////////////////////////////////////////////
// Деструктор: удаляет динамические строки,
// созданные Addltem().
//
AArr::~AArr ()
{
for (int j=0; j<nltems; j++) {
delete [] keys[j];
delete[] items[j];
}
////////////////////////////////////////////////////////////
// Создает новую запись с указателями в keys[] и items[].
//
void AArr::Addltem(const char *key, const char *data)
{
if (nitems < Maxltems) {
keys[nitems] == new char[strlen(key)+1];
items[nitems] = new char[strlen(data)+1] ;
strcpy(keys[nitems], key);
strcpy(items[nitems], data);
n Items++; }
////////////////////////////////////////////////////////////
// Перегруженная индексация: ищет запись с указанным ключом. //
const char *AArr::operator[1 (const char *idx)
(
int j ;
for (j=0; j<nltems; j++)
if (!strcmp(keys[j], idx)) break;
if (j < nitems) return items[j];
else
return error;
}
int main() {
AArr a;
// Несколько записей... a.AddItem("first", "String One!");
a.AddItem("second", "String Two!");
a.AddItem("another", "Another String!");
a.AddItem("one more", "One More String!");
a.AddItem("finish", "That's all folks!");
// Проверка:
char *i;
i = "second";
printf("\n%s: %s\ri", i, a[i]);
i = "one more";
printf ("%s: %s\n", i, a[i]);
i = "abracadabra";
printf ("%s: %s\n", i, a[i]);
i = "finish"; printf("%s: %s\n", i, a[i]);
return 0;
}
Этот пример не требует особых пояснений. Здесь перегружается функция-операция с именем Aarr: : operator []. Получившийся класс ведет себя как массив с “индексами”-строками. Вывод программы показан на рис. 8.3.

Рис. 8.3 Программа Index

Содержание раздела