[C ++] Ковариантные возвращаемые типы - PullRequest
4 голосов
/ 19 августа 2010

У меня есть класс VectorN и класс Vector3, унаследованные от VectorN (которые могут обрабатывать, например, перекрестные продукты). У меня проблемы с определением типов возврата различных операторов. Пример:

class VectorN
{
public:
   VectorN(){};
   virtual VectorN operator*(const double& d) {.....};
   std::vector<double> coords;
};

class Vector3 : public VectorN
{
public:
  Vector3(){};
  virtual Vector3 operator*(const double& d) {....};
};

Этот конкретный пример выдает ошибку C2555:

'Vector3 :: operator *': тип возвращаемой переопределенной виртуальной функции отличается и не является ковариантным от 'VectorN :: operator *', см. Объявление 'VectorN :: operator *'.

Проблема в том, что я не возвращаю ссылку на Vector3, и что класс Vector3 не полностью определен при объявлении operator*. Тем не менее, я хочу, чтобы мой operator* был виртуальным, и я хочу вернуть Vector3, когда я умножу Vector3 на константу (в противном случае, если я сделаю (Vector3*double).crossProduct(Vector3), это вернет ошибку).

Что я могу сделать?

Спасибо!

Ответы [ 2 ]

6 голосов
/ 19 августа 2010

Вам нужен редизайн. Во-первых, предпочтение свободных функций над функциями-членами. Единственные функции-члены, которые вы должны иметь, это те, которым нужен доступ для рядовых.

Начните с этой комбинации:

class VectorN
{
public:
   virtual VectorN& operator*=(double d)
    {
        /* ... */

        return *this;
    };
};


class Vector3 : public VectorN
{
public:
    virtual Vector3& operator*=(double d)
    {
        return static_cast<Vector3&>(VectorN::operator*=(d));
    };
};

Здесь ковариация работает нормально, потому что тип является ссылкой или указателем, и вы повторно используете код. (static_cast является бесплатным, ориентированным на производительность и безопасным, поскольку вы знаете производный тип.)

Затем вы реализуете свои свободные функции:

// optimization: if you're going to make a copy, do it in the parameter list;
// compilers can elide a copy when working with temporaries
VectorN operator*(VectorN v, double d)
{
    // reuse code
    return v *= d;
}

VectorN operator*(double d, VectorN v)
{
    // reuse code
    return v *= d;
}

Сделайте то же самое с Vector3.

Что было сделано, так это то, что вы получили простой способ написания этих операторов, поскольку вы можете использовать ядро ​​оператора, а тип возвращаемого значения совпадает, благодаря ковариации.


Прислушайтесь к предупреждениям, хотя, вероятно, вам это не нужно. И расширения, которые вы хотите сделать, могут быть сделаны с помощью свободных функций, работающих на vector или valarray.

0 голосов
/ 19 августа 2010

Лучшее, что я могу придумать, это заменить тип возвращаемого значения умным указателем и отказаться от ковариации в пользу полиморфизма:

virtual auto_ptr< VectorN > operator*(const double& d);

Причина, по которой я предлагаю это, заключается в том, что вы используете виртуальные функции, поэтомузнать точный тип объекта не обязательно в любом случае.

Основная проблема заключается в том, что вызывающая сторона должна выделять память для объекта, возвращаемого значением.Это хранилище не может изменяться динамически, поэтому вы неизбежно застряли, выделяя объект в куче.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...