0

I'm learning C++ and specifically the operator overloading.

I have the following piece of code:

#include <iostream>
#include <string>

using namespace std;

class Vector2
{
private:
    float x, y;

public:
    Vector2(float x, float y)
        : x(x), y(y) {}
    Vector2 Add(const Vector2& other) const;
    Vector2 operator+(const Vector2& other) const;
    Vector2 operator*(const Vector2& other) const;
    friend ostream& operator << (ostream& stream, const Vector2& other);
    Vector2 Multiply(const Vector2& other) const;
};

ostream& operator << (ostream& stream, const Vector2& other)
{
    stream << other.x << ", " << other.y;
    return stream;
}

Vector2 Vector2::Add(const Vector2& other) const
{
    return Vector2(x + other.x, y + other.y);
}

Vector2 Vector2::operator+(const Vector2& other) const
{
    return Add(other);
}

Vector2 Vector2::Multiply(const Vector2& other) const
{
    return Vector2(x * other.x, y * other.y);
}

Vector2 Vector2::operator*(const Vector2& other) const
{
    return Multiply(other);
}

int main()
{
    Vector2 position(4.0f, 4.0f);
    Vector2 speed(0.5f, 1.5f);
    Vector2 powerup(1.1f, 1.1f);

    Vector2 result = position.Add(speed.Multiply(powerup));
    Vector2 result2 = position + speed * powerup;

    std::cout << result2 << std::endl;

    std::cin.get();
}

Question: if I want this to work, I need to declare my ostream& operator << as friend. Otherwise MS Studio tells me: "Function definition for operator << not found"!

I don't understand why. I don't need to declare the other operators as friend, so why is this necessary in this case?

Thanks.

piquesel
  • 157
  • 9
  • 1
    That's not the error I get. Are you sure it's not "can't access private member `x` of `Vector2`" or something similar? If you get the error "Function definition for operator << not found" you might have another problem in your real code. – Lukas-T Jun 19 '21 at 10:54
  • 1
    Other operators are **member functions** of your class. This one is not. You need to declare it as a `friend` because otherwise it will not be able to access `private` members of the class. – n. m. could be an AI Jun 19 '21 at 10:54
  • 1
    It's not necessary to declare `operator<<()` as a `friend` unless its definition attempts to directly access private or protected members or bases of your class. It is necessary to declare it somehow in any code that attempts to call it (e.g. so the declaration of the `operator<<()` is seen by the compiler before being used in your `main()`). – Peter Jun 19 '21 at 10:55
  • 1
    Does this answer your question? ['friend' functions and << operator overloading: What is the proper way to overload an operator for a class?](https://stackoverflow.com/questions/2828280/friend-functions-and-operator-overloading-what-is-the-proper-way-to-overlo) – anastaciu Jun 19 '21 at 10:56
  • 1
    Remove `using namespace std`, please. – Antonio Jun 19 '21 at 10:57
  • Add a public member function `void Print(ostream& stream) const { stream << x << ", " << y; }` then have the `operator<<` call `other.Print(stream); return stream;`. That way Vector2 can have no friends. – Eljay Jun 19 '21 at 11:35

2 Answers2

4

The operator<< must be defined as non-member function (as well as operator>>).

Let's take a look at the case when our class has defined the operator<< as a member function, we would have to do output like so:

// Member function, lhs is bound to implicit this
ostream& operator<<(ostream&) const; 
Myclass obj;
obj << std::cout;

Why so? Because you know that an overloaded operator is just a function. So, underlying call to this function looks like this:

obj.operator<<(std::cout);

If the operator is a member function, there's no other way. Since we can't modify the library.

So, in order for the operator to access private data members, i.e. the x and y, we have to declare it as a friend.

The arithmetic operators ordinarily should also be non-member functions, to allow conversions for either of the operands. Thought it is not required. These also should not change state of their operands and should produce a new value, which also stimulates to approach them from non-member function.

Also, I would advise you to get rid of the using namespace std and specify namespaces explicitly (or at least avoid mixing up).

rawrex
  • 4,044
  • 2
  • 8
  • 24
1

Operators + and * are declared as member functions of Vector2, so they are naturally able to access private members of Vector2.

However, you can't declare canonical IO-operators (<< and >>) as member-functions. The line

friend ostream& operator << (ostream& stream, const Vector2& other);

is not a declaration of a member function. It simply allows the free/non-member function ostream& operator << (ostream& stream, const Vector2& other); to access private members of Vector2.

Without this line you should get the error

'Vector2::x': cannot access private member declared in class 'Vector2'

(or something similar)


However, the error

"Function definition for operator << not found"

could arise when you have split declaration and definition in your real code. If you have the line

friend ostream& operator << (ostream& stream, const Vector2& other);

in Vector2 you also declared a free function ostream& operator << (ostream& stream, const Vector2& other); and simultaneously make it a friend of Vector2.

If you remove this line, the function isn't declared anywhere. (Of course the last part is only speculation, but the best guess I've got)

Lukas-T
  • 11,133
  • 3
  • 20
  • 30