Стандарты программирования на С++. 101 правило и рекомендация | страница 52
>class String { // ...
> String(const char* text); // Обеспечивает неявное
> // преобразование типов
>};
>bool operator==(const String&, const String&);
>// ... где-то в коде ...
>if (someString == "Hello"){ ... }
Ознакомившись с приведенными выше определениями, компилятор компилирует приведенное сравнение таким образом, как если бы оно было записано в виде >someString == String("Hellо")
. Это слишком расточительно — копировать символы, чтобы потом просто прочесть их. Решение этой проблемы очень простое — определить перегруженные функции, чтобы избежать преобразования типов, например:
>bool operator==(const String& lhs, const string& rhs); // #1
>bool operator==(const String& lhs, const char* rhs); // #2
>bool operator==(const char* lhs, const String& rhs); // #3
Это выглядит как дублирование кода, но на самом деле это всего лишь "дублирование сигнатур", поскольку все три варианта обычно используют одну и ту же функцию. Вряд ли вы впадете в ересь преждевременной оптимизации (см. рекомендацию 8) при такой простой перегрузке, тем более что этот метод слабо применим при проектировании библиотек, когда трудно заранее предсказать, какие именно типы будут использоваться в коде, критическом по отношению к производительности.
[Meyers96] §21 • [Stroustrup00] §11.4, §C.6 • [Sutter00] §6
30. Избегайте перегрузки >&&
, >||
и >,
(запятой)
Мудрость — это знание того, когда надо воздержаться. Встроенные операторы >&&
, >||
и >,
(запятая) трактуются компилятором специальным образом. После перегрузки они становятся обычными функциями с весьма отличной семантикой (при этом вы нарушаете рекомендации 26 и 31), а это прямой путь к трудноопределимым ошибкам и ненадежности. Не перегружайте эти операторы без крайней необходимости и глубокого понимания.
Главная причина отказа от перегрузки операторов >operator&&
, >operator||
и >operator,
(запятая) состоит в том, что вы не имеете возможности реализовать полную семантику встроенных операторов в этих трех случаях, а программисты обычно ожидают ее выполнения. В частности, встроенные версии выполняют вычисление слева направо, а для операторов >&&
и >||
используются сокращенные вычисления.
Встроенные версии >&&
и >||
сначала вычисляют левую часть выражения, и если она полностью определяет результат (>false
для >&&
, >true
для >||
), то вычислять правое выражение незачем — и оно гарантированно не будет вычисляться. Таким образом мы используем эту возможность, позволяя корректности правого выражения зависеть от успешного вычисления левого: