13
14
15
16
17
18
}
if(Initiallnput != NULL)
{
Buffer = new char [strlen(Initiallnput) + 1]; strcpy(Buffer, Initiallnput);
}
else
Buffer = NULL;
// вставить конструктор копий из листинга 9.9
MyString(const MyString& CopySource);
23
// Оператор присвоения копии
MyString& operator= (const MyString& CopySource)
{
if ((this != &CopySource) && (CopySource.Buffer != NULL))
{
if (Buffer != NULL)
// гарантирует глубокую копию с предварительным
резервированием собственного буфера
Buffer = new char [strlen(CopySource.Buffer) + 1];
// копирование оригинала в локальный буфер
strcpy(Buffer, CopySource.Buffer);
}
return *this;
}
40
324 ЗАНЯТИЕ 12. Типы операторов и их перегрузка
I I Деструктор
-MyString ()
{
if (Buffer != NULL)
delete [] Buffer;
}
47:
int GetLengthO
{
return strlen(Buffer);
}
52:
operator const char*()
{
return Buffer;
}
};
58:
int main ()
{
MyString Stringl("Hello ");
MyString String2(" World");
64:
|
cout
|
«
|
"Before assignment:
|
" « endl;
|
65:
|
cout
|
«
|
Stringl « String2
|
« endl;
|
String2 = Stringl;
cout « "After assignment String2 = Stringl: " « endl;
68:
|
cout «
|
Stringl « String2 « endl;
|
69:
|
|
|
return 0;
}
Результат
Before assignment:
Hello World
After assignment String2 = Stringl:
Hello Hello
Анализ
преднамеренно пропустил конструктор копий в этом примере, чтобы сократить объем кода (но при создании подобного класса обязательно добавьте его; см. листинг 9.9). Оператор присвоения копии реализован в строках 25-39. Это очень похоже на конструк тор копий, но с предварительной проверкой, гарантирующей, что оригинал и копия не являются тем же объектом. После успеш ной проверки оператор присвоения копии для класса M y S trin g освобождает сначала свой внутренний буфер, затем повторно резерви рует место для текста копии, а потом использует функцию s t r c p y () для копирования, как показано в строке 36.
Бинарные операторы 325
ПРИМЕЧАНИЕ Еще одно незначительное различие между листингами 12.9 и 9.9 в том, что
функция Getstring () заменена оператором const char*, как демонстри
руют строки 53-56. Этот оператор облегчает использование класса MyString, как показано в строке 68, где один оператор cout используется для отображе ния двух экземпляров класса MyString.
ВНИМАНИЕ!
СОВЕТ
При реализации класса, который управляет динамически распределяемым ре сурсом, таким как символьная строка в стиле С, динамический массив и т.д., всегда следует реализовать (или рассмотреть необходимость реализовать) кон структор копий и оператор присвоения копии в дополнение к конструктору и деструктору.
Если вы не решаете проблему собственности ресурса явно, когда объект ваше го класса копируется, ваш класс неполон и даже опасен для использования.
Чтобы создать класс, который не может быть скопирован, объявите конструктор копий и оператор присвоения копии как закрытый. Объявления (даже не реа лизации) вполне достаточно для компилятора, чтобы передать сообщение об ошибке при любых попытках копирования этого класса при передаче в функцию по значению или при присвоении одного экземпляра другому.
Оператор индексирования([])
Оператор [ ], позволяющий обращаться к классу в стиле массива, называется операто ром индексирования (subscript operator). Типичный синтаксис оператора индексирования таков:
т ип_возвращ аемого_значенияЬ operator [] (тип_индекса& индекс);
Так, при создании такого класса, как M y S trin g , инкапсулирующего класс динамиче ского массива символов c h a r* B u f f e r , оператор индексирования существенно облегчит произвольный доступ к отдельным символам в буфере:
class MyString
{
... другие члены класса
public:
/*const*/ char& operator [] (int Index) /*const*/
{
// возвратить из буфера символ по позиции индекса
}
};
Пример в листинге 12.10 демонстрирует, как оператор индексирования ([ ]) позволяет пользователю перебирать символы, содержавшиеся в экземпляре класса M y S trin g , с ис пользованием обычной семантики массива.
326 ЗАНЯТИЕ 12. Типы операторов и их перегрузка
ЛИСТИНГ 12.10. Реализация оператора индексирования ([ ]) в классе Mystring, обеспечивающего произвольный доступ к символам в буфере MyString::Buffer
#include
#include
using namespace std;
class MyString
{
private:
char* Buffer;
:
// закрытый стандартный конструктор
MyString() {}
1 1 :
public:
// Конструктор
MyString(const char*Initiallnput)
{
if(Initiallnput != NULL)
{
Buffer = new char [strlen (Initiallnput) + lb-
strcpy(Buffer, Initiallnput);
20: }
else
Buffer = NULL;
}
24:
// Конструктор копий: вставить из листинга 9.9
MyString(const MyString& CopySource);
27:
// Оператор присвоения копии: вставить из листинга 12.9
MyString& operator= (const MyString& CopySource);
30:
const char& operator[] (int Index) const
{
if (Index < GetLengthO)
return Buffer[Index];
}
36:
// Деструктор
~MyString()
{
if (Buffer != NULL)
delete [] Buffer;
}
43:
int GetLengthO const
{
return strlen(Buffer);
}
48:
operator const char*()
{
51 return Buffer;
}
:5: int main()
:6: {
cout « "Type a statement: ";
string strlnput;
:9: getline(cin, strlnput);
cl:
|
MyString
|
youSaid(strlnput.c_str());
|
|
|
|
t2:
|
cout
|
«
|
|
"Using
|
operator[]
|
|
for displaying your input:
|
" «
|
endl;
|
-3:
|
|
<
|
t'4:
|
for(int
|
Index
|
= 0;
|
Index
|
youSaid. GetLength () ; ++Index)
|
|
-5:
|
cout
|
|
cout
|
«
|
youSaid [Index]
|
«
|
" ";
|
|
|
|
~6:
|
|
«
|
endl;
|
|
|
|
|
|
|
|
|
i l :
|
cout
|
«
|
|
"Enter
|
index 0 -
|
" «
|
|
Do'stlaringiz bilan baham: |