[c++] Overloading operators in typedef structs (c++)

I want to make a typedef struct called pos (from position) that stores coordinates x and y. I am trying to overload some operators for this struct, but it does not compile.

typedef struct {
    int x;
    int y;

    inline pos operator=(pos a) {
        x=a.x;
        y=a.y;
        return a;
    }

    inline pos operator+(pos a) {
        return {a.x+x,a.y+y};
    }

    inline bool operator==(pos a) {
       if (a.x==x && a.y== y)
          return true;
       else
          return false;
    }
} pos;

I also wanted to know the difference between this:

inline bool operator==(pos a) {
    if(a.x==x && a.y== y)
       return true;
      else
       return false;
}

And this:

bool operator==(pos a) const {
      if(a.x==x && a.y== y)
         return true;
      else
         return false;
}

This question is related to c++ struct typedef operator-keyword

The answer is


The breakdown of your declaration and its members is somewhat littered:

Remove the typedef

The typedef is neither required, not desired for class/struct declarations in C++. Your members have no knowledge of the declaration of pos as-written, which is core to your current compilation failure.

Change this:

typedef struct {....} pos;

To this:

struct pos { ... };

Remove extraneous inlines

You're both declaring and defining your member operators within the class definition itself. The inline keyword is not needed so long as your implementations remain in their current location (the class definition)


Return references to *this where appropriate

This is related to an abundance of copy-constructions within your implementation that should not be done without a strong reason for doing so. It is related to the expression ideology of the following:

a = b = c;

This assigns c to b, and the resulting value b is then assigned to a. This is not equivalent to the following code, contrary to what you may think:

a = c;
b = c;

Therefore, your assignment operator should be implemented as such:

pos& operator =(const pos& a)
{
    x = a.x;
    y = a.y;
    return *this;
}

Even here, this is not needed. The default copy-assignment operator will do the above for you free of charge (and code! woot!)

Note: there are times where the above should be avoided in favor of the copy/swap idiom. Though not needed for this specific case, it may look like this:

pos& operator=(pos a) // by-value param invokes class copy-ctor
{
    this->swap(a);
    return *this;
}

Then a swap method is implemented:

void pos::swap(pos& obj)
{
    // TODO: swap object guts with obj
}

You do this to utilize the class copy-ctor to make a copy, then utilize exception-safe swapping to perform the exchange. The result is the incoming copy departs (and destroys) your object's old guts, while your object assumes ownership of there's. Read more the copy/swap idiom here, along with the pros and cons therein.


Pass objects by const reference when appropriate

All of your input parameters to all of your members are currently making copies of whatever is being passed at invoke. While it may be trivial for code like this, it can be very expensive for larger object types. An exampleis given here:

Change this:

bool operator==(pos a) const{
    if(a.x==x && a.y== y)return true;
    else return false;
}

To this: (also simplified)

bool operator==(const pos& a) const
{
    return (x == a.x && y == a.y);
}

No copies of anything are made, resulting in more efficient code.


Finally, in answering your question, what is the difference between a member function or operator declared as const and one that is not?

A const member declares that invoking that member will not modifying the underlying object (mutable declarations not withstanding). Only const member functions can be invoked against const objects, or const references and pointers. For example, your operator +() does not modify your local object and thus should be declared as const. Your operator =() clearly modifies the local object, and therefore the operator should not be const.


Summary

struct pos
{
    int x;
    int y;

    // default + parameterized constructor
    pos(int x=0, int y=0) 
        : x(x), y(y)
    {
    }

    // assignment operator modifies object, therefore non-const
    pos& operator=(const pos& a)
    {
        x=a.x;
        y=a.y;
        return *this;
    }

    // addop. doesn't modify object. therefore const.
    pos operator+(const pos& a) const
    {
        return pos(a.x+x, a.y+y);
    }

    // equality comparison. doesn't modify object. therefore const.
    bool operator==(const pos& a) const
    {
        return (x == a.x && y == a.y);
    }
};

EDIT OP wanted to see how an assignment operator chain works. The following demonstrates how this:

a = b = c;

Is equivalent to this:

b = c;
a = b;

And that this does not always equate to this:

a = c;
b = c;

Sample code:

#include <iostream>
#include <string>
using namespace std;

struct obj
{
    std::string name;
    int value;

    obj(const std::string& name, int value)
        : name(name), value(value)
    {
    }

    obj& operator =(const obj& o)
    {
        cout << name << " = " << o.name << endl;
        value = (o.value+1); // note: our value is one more than the rhs.
        return *this;
    }    
};

int main(int argc, char *argv[])
{

    obj a("a", 1), b("b", 2), c("c", 3);

    a = b = c;
    cout << "a.value = " << a.value << endl;
    cout << "b.value = " << b.value << endl;
    cout << "c.value = " << c.value << endl;

    a = c;
    b = c;
    cout << "a.value = " << a.value << endl;
    cout << "b.value = " << b.value << endl;
    cout << "c.value = " << c.value << endl;

    return 0;
}

Output

b = c
a = b
a.value = 5
b.value = 4
c.value = 3
a = c
b = c
a.value = 4
b.value = 4
c.value = 3

try this:

struct Pos{
    int x;
    int y;

    inline Pos& operator=(const Pos& other){
        x=other.x;
        y=other.y;
        return *this;
    }

    inline Pos operator+(const Pos& other) const {
        Pos res {x+other.x,y+other.y};
        return res;
    }

    const inline bool operator==(const Pos& other) const {
        return (x==other.x and y == other.y);
    }
 };  

  1. bool operator==(pos a) const{ - this method doesn't change object's elements.
  2. bool operator==(pos a) { - it may change object's elements.

Instead of typedef struct { ... } pos; you should be doing struct pos { ... };. The issue here is that you are using the pos type name before it is defined. By moving the name to the top of the struct definition, you are able to use that name within the struct definition itself.

Further, the typedef struct { ... } name; pattern is a C-ism, and doesn't have much place in C++.

To answer your question about inline, there is no difference in this case. When a method is defined within the struct/class definition, it is implicitly declared inline. When you explicitly specify inline, the compiler effectively ignores it because the method is already declared inline.

(inline methods will not trigger a linker error if the same method is defined in multiple object files; the linker will simply ignore all but one of them, assuming that they are all the same implementation. This is the only guaranteed change in behavior with inline methods. Nowadays, they do not affect the compiler's decision regarding whether or not to inline functions; they simply facilitate making the function implementation available in all translation units, which gives the compiler the option to inline the function, if it decides it would be beneficial to do so.)


Examples related to c++

Method Call Chaining; returning a pointer vs a reference? How can I tell if an algorithm is efficient? Difference between opening a file in binary vs text How can compare-and-swap be used for a wait-free mutual exclusion for any shared data structure? Install Qt on Ubuntu #include errors detected in vscode Cannot open include file: 'stdio.h' - Visual Studio Community 2017 - C++ Error How to fix the error "Windows SDK version 8.1" was not found? Visual Studio 2017 errors on standard headers How do I check if a Key is pressed on C++

Examples related to struct

How to search for an element in a golang slice "error: assignment to expression with array type error" when I assign a struct field (C) How to set default values in Go structs How to check for an empty struct? error: expected primary-expression before ')' token (C) Init array of structs in Go How to print struct variables in console? Why Choose Struct Over Class? How to return a struct from a function in C++? Initializing array of structures

Examples related to typedef

How do I use typedef and typedef enum in C? Overloading operators in typedef structs (c++) What is the difference between 'typedef' and 'using' in C++11? typedef fixed length array Typedef function pointer? C++ template typedef dereferencing pointer to incomplete type uint8_t vs unsigned char typedef struct vs struct definitions Understanding typedefs for function pointers in C

Examples related to operator-keyword

What does double question mark (??) operator mean in PHP How to use comparison operators like >, =, < on BigDecimal What do >> and << mean in Python? How do operator.itemgetter() and sort() work? ' << ' operator in verilog Overloading operators in typedef structs (c++) C++ Double Address Operator? (&&) Concatenating strings doesn't work as expected