Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Operator overloading  (Read 2466 times)

0 Members and 1 Guest are viewing this topic.

julen26

  • Jr. Member
  • **
  • Posts: 89
    • View Profile
    • http://julen26.blogspot.com
Operator overloading
« on: September 23, 2011, 03:13:38 pm »
Hi, i'm trying to design a small physics-engine. I've been coding a Vector and a Entity class, but I get always the same error in the Entity class. Vector class compiles without any error.

Code: [Select]
/home/julen/Proyectos/soccer/physic/Entity.cpp||In member function ‘void Entity::applyForce(Vector2D&, Vector2D&)’:|
/home/julen/Proyectos/soccer/physic/Entity.cpp|32|error: no matching function for call to ‘Vector2D::Vector2D(Vector2D)’|
/home/julen/Proyectos/soccer/physic/Vector2D.h|20|note: candidates are: Vector2D::Vector2D(float, float)|
/home/julen/Proyectos/soccer/physic/Vector2D.h|19|note:                 Vector2D::Vector2D(Vector2D&)|
/home/julen/Proyectos/soccer/physic/Vector2D.h|18|note:                 Vector2D::Vector2D()|


And here is my code:

Vector2D class:
Code: [Select]

/* Constructors */
Vector2D::Vector2D()
{
    reset();
}
Vector2D::Vector2D(Vector2D & vector)
{
    m_elements[0] = vector[0];
    m_elements[1] = vector[1];
}
Vector2D::Vector2D(float x, float y)
{
    m_elements[0] = x;
    m_elements[1] = y;
}
Vector2D::~Vector2D()
{
    reset();
}
...
Vector2D & Vector2D::operator = (Vector2D & vector)
{
    setVector(vector);
    return *this;
}
...
Vector2D & Vector2D::operator += (Vector2D & vector)
{
    m_elements[0] += vector[0];
    m_elements[1] += vector[1];
    return *this;
}
...
Vector2D Vector2D::operator + (Vector2D & vector)
{
    Vector2D v(m_elements[0] + vector[0], m_elements[1] + vector[1]);
    return v;
}
Vector2D Vector2D::operator - (Vector2D & vector)
{
    Vector2D v(m_elements[0] - vector[0], m_elements[1] - vector[1]);
    return v;
}
...


Entity class:

Code: [Select]
...
void Entity::applyForce(Vector2D & force, Vector2D & pointOfContact)
{
    m_totalForce += force;
    Vector2D arm = pointOfContact - m_centerOfMass; //HERE I GET THE ERROR
    m_totalTorque += arm.perpDotProduct(force);
}
...


Hope someone can help me.
Thanks.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Operator overloading
« Reply #1 on: September 23, 2011, 03:19:06 pm »
All the parameters of your operators are non-const references. This means that you intend to modify them in the function (which is not true), thus implying that only named variables can be passed to these operators.

Code: [Select]
void f(int & x)
{
    x = 5;
}

int a = 5;
int b = 2;

f(5); // not ok, '5' is not a named variable
f(a - b); // not ok, 'a - b' is not a named variable
f(a); // ok


So you must use const references to solve the problem.

You should also make operators non-member functions as much as possible, and avoid defining trivial functions that would otherwise be generated by the compiler (copy constructor, operator=, destructor).
Laurent Gomila - SFML developer

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Operator overloading
« Reply #2 on: September 23, 2011, 03:21:40 pm »
I would use global functions for + and - operators.
Code: [Select]
Vector2D operator+ (Vector2D lhs, Vector2D rhs)
{
    return Vector2D(lhs[0] + rhs[0], lhs[1] + rhs[1]);
}

And you should consider const-correctness. Parameters that aren't changed by the function should be passed as copies or as references to const. Since the vector class is propably small, it is cheap to copy. But the copy constructor needs a const reference:
Code: [Select]
Vector2D::Vector2D(const Vector2D& origin)
: m_elements(origin.m_elements)
{
}

But if the class contains only an array of 2 elements, you needn't define the copy constructor on your own. The compiler-generated one will do the right thing. Same for copy assignment operator and destructor (Rule of the Big Three).

Take a look at the SFML vector classes and their implementations. SFML is one of the few graphic libraries who overloads operators correctly (in contrast to Irrlicht or Ogre, for example).
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Disch

  • Full Member
  • ***
  • Posts: 220
    • View Profile
Operator overloading
« Reply #3 on: September 23, 2011, 03:56:13 pm »
Quote from: "Laurent"
You should also make operators non-member functions as much as possible,

Quote from: "Nexus"
I would use global functions for + and - operators.


Can you guys elaborate your rationale for this?  I feel the exact opposite.  Putting operators in their respective class whenever possible keeps the code more organized, IMO.  The only time I put them outside the class is when I have to (if the lhs isn't an object).

I'm interested in hearing other viewpoints.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Operator overloading
« Reply #4 on: September 23, 2011, 04:02:14 pm »
There are several reasons.

1. They don't need to be inside the class, because they use only public members (and if they wouldn't, 'friend' could help). And it's always good practice to keep the set of direct members as minimal as possible.

2. It's more symetrical between lhs and rhs.

3. (the most important) If T can be constructed from other types, you can only benefit of the implicit conversion for rhs if your operator is a member; if it's a free function you can have it for both lhs and rhs.

Code: [Select]
class String
{
public:

    String(const char* str);
    bool operator ==(const String& other) const;
};

String s;

s == s; // ok
s == "hello"; // ok
"hello" == s; // won't compile, you need a non-member operator== anyway
Laurent Gomila - SFML developer

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Operator overloading
« Reply #5 on: September 23, 2011, 04:06:53 pm »
Generally, one should try to keep the direct public interface of a class small. Functions that can be implemented without needing to access private data should be global to increase encapsulation. Of course, one can't apply this principle everywhere, but it is a good guide. A negative example for this is std::string, see Monoliths Unstrung.

In case of operators, there is another point: Global operators are symmetric, while member operators are not. The latter require that the first argument be of type of the class itself, while the second argument need only be convertible to the type. Thus, it might happen that a + b is possible, but b + a results in a compile error.

On the other side, member operators don't really have an advantage. A class's interface consists of its public members and types as well as the functions and types defined in the same header. Herb Sutter emphasizes this point again and again in his book Exceptional C++, you'll probably also find this on GotW.

Edit: Argh, Laurent :D
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

julen26

  • Jr. Member
  • **
  • Posts: 89
    • View Profile
    • http://julen26.blogspot.com
Operator overloading
« Reply #6 on: September 23, 2011, 04:54:02 pm »
Thank you about all this information and advices, I've solved all my problems.

  • Guest
Operator overloading
« Reply #7 on: September 29, 2011, 12:45:30 pm »
Operator overloading is very important concepts in the all the languages,
before that you have understand properly while studying the c++ basics,

Example Program:
class Complex
{
public:
        Complex(double re,double im)
                :real(re),imag(im)
                {};
        Complex operator+(const Complex& other);
        Complex operator=(const Complex& other);
private:
        double real;
        double imag;
};
Complex Complex::operator+(const Complex&  other)
{
    double result_real = real + other.real;
    double result_imaginary = imag + other.imag;
    return Complex( result_real, result_imaginary );
}


Cegonsoft
_________________________
Cegonsoft foundation