1

I'm writing a simple C++ class called Vector2f. I have a class file called Vector2f.cpp and a header file called Vector2f.h.

My Vector2f class has a function called abs which returns a new Vector2f with the absolute value of each of the components of the original Vector2f. I am using the cmath library. However when I try to use cmath's abs function, it thinks I'm referring to some undefined function Vector2f::abs(float) rather than cmath's abs function. Why is there a naming conflict here? Shouldn't C++ be able to resolve that a function called abs that takes a float is only defined in cmath and not in Vector2f.h

Here is my code:

My header file:

//Vector2f.h

#ifndef VECTOR2F_H
#define VECTOR2F_H

class Vector2f
{
private:
    float x;
    float y;

public:
    Vector2f(float x, float y);
    float length();
    float dot(Vector2f r);
    Vector2f normalized();
    Vector2f rot(float angle);
    Vector2f add(Vector2f r);
    Vector2f add(float r);
    Vector2f sub(Vector2f r);
    Vector2f sub(float r);
    Vector2f mul(Vector2f r);
    Vector2f mul(float r);
    Vector2f div(Vector2f r);
    Vector2f div(float r);
    Vector2f abs();
    float getX();
    float getY();

};

#endif // VECTOR2F_H

My class file:

//Vector2f.cpp

#ifndef M_PI
#define M_PI 3.14159265358979323846264338327950288
#endif // M_PI
#include "Vector2f.h"
#include <cmath>

Vector2f::Vector2f(float x, float y)
{
    this -> x = x;
    this -> y = y;
}
float Vector2f::length()
{
    return (float)sqrt(x * x + y * y);
}

float Vector2f::dot(Vector2f r)
{
    return x * r.getX() + y * r.getY();
}

Vector2f Vector2f::normalized()
{
    float length = Vector2f::length();

    float xnormal = x/length;
    float ynormal = y/length;

    return Vector2f(xnormal, ynormal);
}

Vector2f Vector2f::rot(float angle)
{
    double rad = angle * M_PI / 180.0;
    double c = cos(rad);
    double s = sin(rad);

    return Vector2f((float)(x * c - y * s), (float)(x * s + y * c));
}

Vector2f Vector2f::add(Vector2f r)
{
    return Vector2f(x + r.getX(), y + r.getY());
}

Vector2f Vector2f::add(float r)
{
    return Vector2f(x + r, y + r);
}

Vector2f Vector2f::sub(Vector2f r)
{
    return Vector2f(x - r.getX(), y - r.getY());
}

Vector2f Vector2f::sub(float r)
{
    return Vector2f(x - r, y - r);
}
Vector2f Vector2f::mul(Vector2f r)
{
    return Vector2f(x * r.getX(), y * r.getY());
}

Vector2f Vector2f::mul(float r)
{
    return Vector2f(x * r, y * r);
}
Vector2f Vector2f::div(Vector2f r)
{
    return Vector2f(x / r.getX(), y / r.getY());
}

Vector2f Vector2f::div(float r)
{
    return Vector2f(x / r, y / r);
}
Vector2f Vector2f::abs()
{
    //I get the error, "error: no matching function for call to 'Vector2f::abs(float&)'", here
    //when trying to call abs(x) and abs(y)
    float xabs = abs(x); 
    float yabs = abs(y);
    return Vector2f(xabs, yabs);
}
float Vector2f::getX()
{
    return x;
}
float Vector2f::getY()
{
    return y;
}

My main file:

//main.cpp

#include <iostream>
#include "Vector2f.h"

using namespace std;

int main()
{
    Vector2f a(1.0f,2.0f);

    cout<<a.getX()<<','<<a.getY()<<endl;

    cout<<a.abs()<<endl;

    return 0;
}

Any help would be appreciated.

Edit:

Error message:

error: no matching function for call to 'Vector2f::abs(float&)'

at line 80:

float xabs = abs(x);

error: no matching function for call to 'Vector2f::abs(float&)'

at line 81:

float yabs = abs(y);
Orren Ravid
  • 560
  • 1
  • 6
  • 24

1 Answers1

3

The compiler does an unqualified lookup of abs. What happens then depends on what you include and if there is a using declaration (and interestingly on the compiler). Everything in cmath is defined in namespace std, so you have to qualify your call with std::.

Vector2f Vector2f::abs()
{
    //I get the error, "undefined reference to `Vector2f::abs(float)'", here
    //when trying to call abs(x) and abs(y)
    float xabs = std::abs(x); 
    float yabs = std::abs(y);
    return Vector2f(xabs, yabs);
}

If you have a using std::abs or using namespace std somewhere before Vector2d::abs, you can qualify with ::abs only. Compilers are allowed to declare C functions such as abs in the global namespace in addition to namespace std, so depending on the compiler using ::abs may work or not without using declarations at all. Clang 3.8 accepts the code, gcc does not.

PS: I would expect a function Vector2f::abs to compute the vector norm and not a vector with absolute values of the original components. But then I am not a mathematician.

Jens
  • 9,058
  • 2
  • 26
  • 43
  • Yea I just edited my question with the proper implementation. I still get a different error though. – Orren Ravid Aug 24 '16 at 06:43
  • Also I have a normalized function defined as well separate from the absolute value function. Abs is more of a convenience for game programming than a mathematical property of vectors. :P – Orren Ravid Aug 24 '16 at 06:48
  • @OrrenRavid I still see `float xabs = abs(x);` in the question. In general, it would be better to post minimal examples with the complete error message. – Jens Aug 24 '16 at 06:48
  • How would I do so for this example? Should I get rid of additional functions in my class? – Orren Ravid Aug 24 '16 at 06:50
  • @OrrenRavid This is OT, but I remember vector norm and a normalized vector to be two different things. The first is a scalar, the second a vector of length 1. But it could well be that your domain uses different conventions. – Jens Aug 24 '16 at 06:50
  • I got the error: "error: '::abs' has not been declared" – Orren Ravid Aug 24 '16 at 07:06
  • Another solution found in this thread: http://stackoverflow.com/questions/15217936/problems-with-cmath-overloaded-functions-c said to add the header #include to the class file and that worked as well. – Orren Ravid Aug 24 '16 at 07:14