Язык программирования C++. Вводный курс


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


Рассмотрим операторы равенства в нашем классе 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. Разумеется, его не существует, поэтому компилятор говорит об ошибке.

Но можно же создать объект класса String из C-строки с помощью конструктора класса. Почему компилятор не выполнит неявно такое преобразование:

if ( String( "tulip" ) == flower )  //правильно: вызывается оператор-член

Причина в его неэффективности. Перегруженные операторы не требуют, чтобы оба операнда имели один и тот же тип. К примеру, в классе Text определяются следующие операторы равенства:

class Text {

public:

   Text( const char * = 0 );

   Text( const Text & );

 

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

   bool operator==( const char * ) const;

   bool operator==( const String & ) const;

   bool operator==( const Text & ) const;

 

   // ...

};

и выражение в main()

можно переписать так:

if ( Text( "tulip" ) == flower )  // вызывается Text::operator==()

Следовательно, чтобы найти подходящий для сравнения оператор равенства, компилятору придется просмотреть все определения классов в поисках конструктора, способного привести левый операнд к некоторому типу класса. Затем для каждого из таких типов нужно проверить все ассоциированные с ним перегруженные операторы равенства, чтобы понять, может ли хоть один из них выполнить сравнение. А после этого компилятор должен решить, какая из найденных комбинаций конструктора и оператора равенства (если таковые нашлись) лучше всего соответствует операнду в правой части! Если потребовать от компилятора выполнения всех этих действий, то время трансляции программ C++ резко возрастет. Вместо этого компилятор просматривает только перегруженные операторы, определенные как члены класса левого операнда (и его базовых классов, как мы покажем в главе 19).




Начало  Назад  Вперед



Книжный магазин