Базовый синтаксис перегрузки операторов в C ++ - PullRequest
7 голосов
/ 06 февраля 2012

Мне трудно сформулировать вопрос о том, что я пытаюсь задать, поэтому приведу пример:

Скажем, мы работаем над 3d-системой, в которой мы определили векторный класс, Vec3. Мы перегружаем некоторые арифметические операторы для очевидных резонов. Среди них мы перегружаем оператор *, чтобы он возвращал скалярное произведение двух векторов. Теперь наш код должен выглядеть примерно так:

class Vec3{
private:
    float x, y, z;
public:
    float operator*(const Vec3&) const; //dot product
.
.
.

Теперь скажите, что мы хотим иметь возможность масштабировать наш вектор, используя оператор * с чем-то, скажем, с плавающей точкой. Это можно сделать, объявив следующее:

    Vec3 operator*(const float) const;
    friend Vec3 operator*(const float, const Vec3&);

Это приводит к двум перегрузкам и Мне интересно, есть ли способ сделать это только с одной , то есть, скажем, мы объявляем это вместо двух вышеуказанных строк:

    friend Vec3 operator*(const Vec3&, const Vec3&);

, а затем добавьте значения по умолчанию для Vec3 ctor для обработки преобразования из числа с плавающей запятой.

Этот последний пример будет работать для:

    Vec3 someVec3 = 1.0 * otherVec3; //through friend Vec3 operator*(const float, const Vec3&)

однако не для этого:

    Vec3 someVec3 = otherVec3 * 1.0;

поскольку компилятор не будет знать, какой из двух использовать:

    friend Vec3 operator*(const float, const Vec3&); //the one we want to use
or
    float operator*(const Vec3&) const; //the one for the dot product

Есть предложения?

Спасибо!

Ответы [ 3 ]

5 голосов
/ 06 февраля 2012

В этом случае я бы изначально посоветовал не перегружать оператора, потому что как ваши пользователи узнают, представляет ли * точечный или перекрестный продукт (оба значения разумны в зависимости от ожидаемого использования клиента). Я бы на самом деле предложил просто не поддерживать operator* и делать это с dot, cross и scale членами. Тогда вам не нужно беспокоиться о множественных перегрузках, и вашим пользователям ясно, что они получают.

Однако, если вы хотите продолжить работу с операторами, нет ничего плохого в двух перегрузках. Создание фиктивной Vec3 для масштабирования не только семантически некорректно, но и добавляет небольшое количество ненужных накладных расходов.

2 голосов
/ 06 февраля 2012

Boost.Operators может сделать большую часть работы котельной плиты за вас.Например:

class Vec3 
  : boost::multipliable2<Vec3, float>
{
public:
   // ... 

   Vec3 operator*=(float);
   // Vec3 operator*(Vec3, const float&) and
   // Vec3 operator*(const float&, Vec3) auto-generated
   // by multipliable. 
};
1 голос
/ 06 февраля 2012

В паре перегрузок нет ничего плохого, особенно если их легко реализовать друг с другом:

Vec3 operator*(const float scale, const Vec3& vec)
{ return vec * scale; }

Трудно сделать это проще, чем это!

...