У меня проблемы с перегрузкой оператора оператор-функция - PullRequest
2 голосов
/ 15 декабря 2011

Компилятор выдает ошибку при попытке вычесть два объекта Point3D. Я получаю эту ошибку:

Invalid operands to binary expression ('Point3D' and 'Point3D')

Вот что у меня есть в моем Vector3D.h:

#include "Point3D.h"
using namespace std;
class Vector3D
{
    friend const Point3D operator+(const Point3D& a, const Vector3D& b);
    friend const Vector3D operator-(const Point3D& a, const Point3D& b);

public:

    Vector3D() {}
    Vector3D(float x, float y, float z);
    Vector3D(Point3D const& originPoint, float theta, float distance);
    float getX() const {return x;}
    float getY() const {return y;}
    float getZ() const {return z;}
    static Vector3D minus(Point3D const& destination, Point3D const& origin);
    Vector3D operator-(Vector3D const& other) const;
    float dot(Vector3D const& other) const;
    static float angleBetweenTwoVectorsZeroToPi(Vector3D const& a, Vector3D const& b);
    static float angleBetweenTwoVectorsZeroToTwoPi(Vector3D const& a, Vector3D const& b);
    Vector3D normalize() const;
    float length() const;
    //const float * const getArray() const {return &x;}
    Vector3D multiply(float scalar) const;
    bool operator==(Vector3D const& v) const;
    float operator[] (int i) const;
private:
    float x;
    float y;
    float z;
};

Файл Vector3D.cpp, который определяет бинарные операторы:

#include "Vector3D.h"
#include "Math3D.h"
#include <math.h>
#include "MathConstants.h"

Vector3D::Vector3D(float x, float y, float z):
x(x), y(y), z(z)
{}

Vector3D::Vector3D(Point3D const& originPoint, float theta, float distance) 
{
    Point3D endPoint = Math3D::calcaultePoint3D(originPoint, theta, distance);
    Vector3D result = minus(endPoint, originPoint);
    this->x = result.x;
    this->y = result.y;
    this->z = result.z;

}

Vector3D Vector3D::minus(Point3D const& destination, Point3D const& origin)
{
    return Vector3D(destination.getX() - origin.getX(), 
                    destination.getY() - origin.getY(), 
                    destination.getZ() - origin.getZ());
}

Vector3D Vector3D::operator-(Vector3D const& other) const {
    return Vector3D(x-other.x, y-other.y, z-other.z);
}

float Vector3D::dot(const Vector3D &other) const
{
    return x * other.x + y * other.y + z * other.z;
}



float Vector3D::length() const
{
    return sqrtf(dot(*this));
}

Vector3D Vector3D::normalize() const
{
    float len = length();
    return Vector3D(getX()/len, getY()/len, getZ()/len);
}

Vector3D Vector3D::multiply(float scalar) const {
    return Vector3D(x * scalar, y * scalar, z * scalar);
}

float Vector3D::angleBetweenTwoVectorsZeroToPi(const Vector3D &a, const Vector3D &b)
{
    /*
     *  The result is between 0 and PI
     */
    Vector3D unitA = a.normalize();
    Vector3D unitB = b.normalize();
    return acos(unitA.dot(unitB));

}

bool Vector3D::operator==(const Vector3D &v) const {
    return (x == v.x) && (y == v.y) && (z == v.z);
}

float Vector3D::operator[](int i) const {
    return (&x)[i];
}

float Vector3D::angleBetweenTwoVectorsZeroToTwoPi(const Vector3D &a, const Vector3D &b)
{
    /*
     *  The result is between 0 and 2PI
     *
     *  "Assuming a = [x1,y1] and b = [x2,y2] are two vectors with their bases at the 
     *  origin, the non-negative angle between them measured counterclockwise 
     *  from a to b is given by
     *
     *  angle = mod(atan2(x1*y2-x2*y1,x1*x2+y1*y2),2*pi);
     *
     *  As you can see, this bears a close relationship to the three-dimensional 
     *  formula I wrote last July 10. The quantities, x1*y2-x2*y1 and x1*x2+y1*y2 
     *  are, respectively, the sine and cosine of the counterclockwise angle from 
     *  vector a to vector b, multiplied by the product of their norms - that is, their 
     *  cross product and the dot product restricted to two dimensions. The 'atan2' 
     *  function then gives the angle between them ranging from -pi to +pi, and the 
     *  'mod' operation changes this so as to range from 0 to 2*pi, as you requested."
     *
     *  Roger Stafford
     *  http://www.mathworks.com/matlabcentral/newsreader/view_thread/151925
     */
    float resultNegPiToPosPi = atan2f(a.x*b.y-b.x*a.y, a.x*b.x+a.y*b.y);
    if (resultNegPiToPosPi < 0.0f)
    {
        resultNegPiToPosPi = resultNegPiToPosPi + 2*MathConstants::PI;
    }
    return resultNegPiToPosPi;
}


const Point3D operator+(const Point3D& a, const Vector3D& b) {return Point3D(a.getX()+b.getX(), a.getY()+b.getY(), a.getZ()+b.getZ());}


const Vector3D operator-(const Point3D& a, const Point3D& b) {return Vector3D(a.getX()-b.getX(), a.getY()-b.getY(), a.getZ()-b.getZ());}

Здесь я пытаюсь вычесть Point3D из другого:

void AnimationService::handlePlayerMovement(double lastTime, double currentTime, Vector3D vector) {

    Point3D a;
    Point3D b;
    Vector3D result = a - b; // this is the problem line
}

Странно, что двоичный файл operator+ работает, но по какой-то причине operator- выдает ошибку Может кто-нибудь сказать мне, что я делаю не так?

Ответы [ 2 ]

4 голосов
/ 15 декабря 2011

Для быстрого исправления сделайте эту operator- бесплатной функцией вместо друга Vector3D.Дружба нужна только тогда, когда вы хотите получить доступ к private участникам, чего вы не делаете для Point3D (вы используете общедоступные методы получения), и чего вы особенно не делаете для Vector3D (вы используете конструктор для его непосредственного построенияиз значений).

То же самое относится и к operator+, дружба здесь не нужна.

Теперь рассмотрим, почему ваш код не работает:

Если a friend объявление сначала найдено в теле класса, и оно не объявлено во вложенном пространстве имен после объявления класса, тогда функция может быть найдена только путем поиска, зависящего от аргумента, то есть она не будетнайдено, если ни один из аргументов не относится к типу класса, которому он принадлежит.Вы можете исправить это, либо сделав их свободными функциями, когда дружба не нужна, либо явно объявив их вне тела класса Vector3D снова в заголовке, например:

class Vector3D{
  friend const Point3D operator+(const Point3D& a, const Vector3D& b);
  friend const Vector3D operator-(const Point3D& a, const Point3D& b);
public:
  // bla bla, yadda yadda
};

// also *declare* them here
const Point3D operator+(const Point3D& a, const Vector3D& b);
const Vector3D operator+(const Point3D& a, const Point3D& b);

Для тех,язык адвокат волнуется, вот соответствующий стандартный абзац:

§7.3.1.2 [namespace.memdef] p3

[...] Если объявление friend в нелокальном классе сначала объявляет классили функция. Другим классом или функцией является член внутреннего пространства имен. Имя друга не найдено ни в неквалифицированном поиске, ни в квалифицированном поиске, пока не будет предоставлено соответствующее объявление в этой области пространства имен (ни до, ни после определения класса, предоставляющего дружбу).[...]

3 голосов
/ 15 декабря 2011

Когда единственным объявлением функции является объявление friend, я считаю, что функция обнаруживается только тогда, когда один из ее аргументов является типом, в котором она была объявлена.Так как operator + использует Vector3D, компилятор ищет его внутри Vector3D.Поскольку оператор принимает только Point3D, компилятор ищет внутри Point3D, но не Vector3D, и поэтому не находит оператора.

Как сказал Xeo, переместите объявления функций за пределы классов, и это должно работать.

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