Перегруженной бинарной операции
Это правило относится к числу тех, которые будут изменены с улучшением качества компиляторов. Рассмотрим следующее, простое для понимания дополнение к классу string из листинга 7 на странице 155:
class string
{
enum special_ { special };
string( special_ ) {}; // ничего не делает.
// ...
public:
const string operator+( const
string r ) const;
// ...
};
//------------------------------------------------------------
const string::operator+( const string r ) const
{
string tmp( special ); // создать пустой объект
tmp.buf = new char[ strlen(buf) + strlen(r.buf) + 1 ];
strcpy( tmp.buf, buf );
strcat( tmp.buf, r.buf );
return tmp;
}
Многие компиляторы, получив вышеуказанное, генерируют довольно неэффективный код. Объект tmp
должен инициализироваться при вызове конструктора; здесь это не очень дорого, но обычно это ведет к значительно большим расходам. Конструктор копии должен быть вызван для выполнения оператора return, и сам объект также должен быть уничтожен.
Иногда вы можете улучшить такое поведение путем перегрузки встроенного псевдонима для операции приведения типа:
class string
{
string(const char *left, const char *right );
public:
const string string::operator+( const string r ) const
;
};
//-----------------------------------------------------------
string::string(const char *left, const char *right )
{
buf = new char[ strlen(left) + strlen(right) + 1 ];
strcpy( buf, left );
strcat( buf, right );
}
//-----------------------------------------------------------
inline const
string::operator+( const string r ) const
{
return string(buf, r.buf);
}
Более эффективные компиляторы здесь на самом деле рассматривают следующее:
string s1, s2;
s1 + s2;
как если бы вы сказали следующее (вы не можете сделать этого сами, потому что buf
является закрытым):
string(s1.buf, s2.buf)
Полезный результат заключается в устранении неявного вызова конструктора копии в операторе return в первом варианте реализации.