编译器在尝试减去两个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-
给了我错误。谁能告诉我我做错了什么?
答案 0 :(得分:4)
要快速解决问题,请将operator-
设为免费功能,而不是Vector3D
的朋友。只有当您想要访问private
成员Point3D
时才需要友谊(您使用公共获取者),而您对Vector3D
尤其不做构造函数从值中直接构造它。
operator+
也是如此,这里不需要友谊。
现在问你代码失败的原因:
如果在类体中找到friend
声明 first ,并且在类声明后未在封闭命名空间中声明它,那么该函数只能通过参数找到依赖查找,意味着如果所有参数都不属于它的朋友,则不会找到它。你可以通过在不需要友谊时使它们成为自由函数,或者通过在标题中再次明确地将它们声明为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
声明首先声明一个类或函数,那么友元类或函数是最内层封闭命名空间的成员。 在该命名空间范围内提供匹配声明(在授予友谊的类定义之前或之后),通过非限定查找或限定查找找不到朋友的姓名。 [...]
答案 1 :(得分:3)
当函数的唯一声明是friend
声明时,我相信只有在其中一个参数是声明它的类型时才能找到该函数。由于operator +采用Vector3D,编译器在查找Vector3D时会查看它。由于仅运算符采用Point3D,编译器在Point3D内部而不是Vector3D,因此找不到运算符。
正如Xeo所说,将函数声明移到类之外,它应该可以工作。