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

String name;

name = "Sherlock"; // использование оператора operator=( char * )

(Операторы присваивания, отличные от копирующих, мы рассмотрим в разделе 15.3.)

Во втором наборе есть всего один оператор – взятия индекса:

// перегруженный оператор взятия индекса

char& operator[]( int );

Он позволяет программе индексировать объекты класса String точно так же, как массивы объектов встроенного типа:

if ( name[0] != 'S' )

cout "увы, что-то не так\n";

(Детально этот оператор описывается в разделе 15.4.)

В третьем наборе определены перегруженные операторы равенства для объектов класса String. Программа может проверить равенство двух таких объектов или объекта и C-строки:

// набор перегруженных операторов равенства

// str1 == str2;

bool operator==( const char * );

bool operator==( const String & );

Перегруженные операторы позволяют использовать объекты типа класса с операторами, определенными в главе 4, и манипулировать ими так же интуитивно, как объектами встроенных типов. Например, желая определить операцию конкатенации двух объектов класса String, мы могли бы реализовать ее в виде функции-члена concat(). Но почему concat(), а не, скажем, append()? Выбранное нами имя логично и легко запоминается, но пользователь все же может забыть, как мы назвали функцию. Зачастую имя проще запомнить, если определить перегруженный оператор. К примеру, вместо concat() мы назвали бы новую операцию operator+=(). Такой оператор используется следующим образом:

#include "String.h"

int main() {

String name1 "Sherlock";

String name2 "Holmes";

name1 += " ";

name1 += name2;

if (! ( name1 == "Sherlock Holmes" ) )

cout "конкатенация не сработала\n";

}

Перегруженный оператор объявляется в теле класса точно так же, как обычная функция-член, только его имя состоит из ключевого слова operator, за которым следует один из множества предопределенных в языке C++ операторов (см. табл. 15.1). Так можно объявить operator+=() в классе String:

class String {

public:

// набор перегруженных операторов +=

String& operator+=( const String & );

String& operator+=( const char * );

// ...

private:

// ...

};

и определить его следующим образом:

#include cstring

inline String& String::operator+=( const String &rhs )

{

// Если строка, на которую ссылается rhs, непуста

if ( rhs._string )

{

String tmp( *this );

// выделить область памяти, достаточную

// для хранения конкатенированных строк

_size += rhs._size;

delete [] _string;

_string = new char[ _size + 1 ];

// сначала скопировать в выделенную область исходную строку

// затем дописать в конец строку, на которую ссылается rhs

strcpy( _string, tmp._string );

strcpy( _string + tmp._size, rhs._string );

}

return *this;

}

inline String& String::operator+=( const char *s )

{

// Если указатель s ненулевой

if ( s )

{

String tmp( *this );

// выделить область памяти, достаточную

// для хранения конкатенированных строк

_size += strlen( s );

delete [] _string;

_string = new char[ _size + 1 ];

// сначала скопировать в выделенную область исходную строку

// затем дописать в конец C-строку, на которую ссылается s

strcpy( _string, tmp._string );

strcpy( _string + tmp._size, s );

}

return *this;

}

15.1.1. Члены и не члены класса

Рассмотрим операторы равенства в нашем классе String более внимательно. Первый оператор позволяет устанавливать равенство двух объектов, а второй – объекта и C-строки:

#include "String.h"

int main() {

String flower;

// что-нибудь записать в переменную flower

if ( flower == "lily" ) // правильно

// ...

else

if ( "tulip" == flower ) // ошибка

// ...

}

При первом использовании оператора равенства в main() вызывается перегруженный operator==(const char *) класса String. Однако на второй инструкции if компилятор выдает сообщение об ошибке. В чем дело?

Перегруженный оператор, являющийся членом некоторого класса, применяется только тогда, когда левым операндом служит объект этого класса. Поскольку во втором случае левый операнд не принадлежит к классу String, компилятор пытается найти такой встроенный оператор, для которого левым операндом может быть C-строка, а правым – объект класса String. Разумеется, его не существует, поэтому компилятор говорит об ошибке.