Exploring Operator Overloading w/ Jamie King's Code

  • Thread starter yungman
  • Start date
  • Tags
    Operator
In summary: The code above would appear to have been written by someone who is unaware that every class member function has an implied first parameter, a pointer to the class instance.
  • #1
yungman
5,755
293
I want to start a thread on Operator overloading for related question.

I watched this youtube video and I like the way Jamie King write the operator overloading function:
This is the program I copied from him:
C++:
#include <iostream>
using namespace std;
struct Vector
{int x; int y;};
//Below is another way to write operator function.
Vector operator+(const Vector& left, const Vector& right)
{    Vector ret;
    ret.x = left.x + right.x;
    ret.y = left.y + right.y;
    return ret;
}
/*Vector operator+( const Vector& right)//normal way of writing operator function.
{    Vector ret;
    ret.x = x + right.x;
    ret.y = y + right.y;
    return ret;
}*/
int main()
{    Vector v1; v1.x = 2; v1.y = 3;
    Vector v2; v2.x = 1; v2.y = 4;
    Vector result; //result = v1 + v2;
     result = operator+(v1, v2);
    cout << " result.x = " << result.x << "  result.y = " << result.y << "\n\n";
}

He uses Vector operator+(Vector &left, Vector&right){}. then in main() result = operator+(v1,v2). To me, this is a lot more descriptive.

Is there anything wrong with writing like this instead of the conventional Vector operatort+(Vector&right){}?

I really find youtube video very helpful, much more so than reading online articles.
 
Technology news on Phys.org
  • #2
The difference is that in his case you are explicitly calling the operator+() function and missing out on the operator overloading feature of invisibility when you define it as operator:

C++:
// INTEGER Math
int a = 1;
int b = 2;
int c;

// regular integer addition
c= a + b;

// commutative property of addition
c = b + a;

C++:
// VECTOR Math
Vector v1; v1.x=1; v1.y=1;
Vector v2; v.x=2; v2.y=2;
Vector v3;

// looks like regular vector addition (v3 = v1.operator+(v2); is nicely hidden from view)
v3 = v1+v2;

// and has commutativity (v3 = v2.operator+(v1); is nicely hidden from view)
v3 = v2 + v1;
 
  • Like
Likes FactChecker
  • #3
The uncommented version is silly.
C++:
Vector operator+(const Vector& left, const Vector& right)
{    Vector ret;
    ret.x = left.x + right.x;
    ret.y = left.y + right.y;
    return ret;
}
In this implementation, operator+() has three parameters: this, left, and right. The code above would appear to have been written by someone who is unaware that every class member function has an implied first parameter, a pointer to the class instance.
I didn't watch the video, but I really hope that the video's author made the point that this is a naive version.
 
Last edited:
  • Like
Likes pbuk, jedishrfu and FactChecker
  • #4
Imagine what some typical mathematical expressions would look like with that approach:
v5 = 5*v1+12*(v2-3*v3); // With operator overloading, this can be defined to work as-is

Convert it to the approach that you prefer and see if you still prefer it.
 
  • Like
Likes yungman
  • #5
Thanks guys. I see your point. If over loading is about making struct and class object look like using simple operator, you have the point. I like it because it explain how the mechanism of the operator works.
 
  • #6
Mark44 said:
I didn't watch the video, but I really hope that the video's author made the point that this is a naive version.
Yes indeed. In fact by reference to the link I posted to the C++ documentation in the similarly-themed thread the canonical implementation of 2D vector addition overloads would be (corrected thanks to this post this post)
C++:
class Vector
{
public:
  Vector& operator+=(const Vector& rhs) // compound assignment (does not need to be a member,
  {                           // but often is, to modify the private members)
    x += rhs.x; // Note correction from *this.x += rhs.x;
    y += rhs.y; // see link in post     *this.y += rhs.y;
    return *this; // return the result by reference
  }

  // friends defined inside class body are inline and are hidden from non-ADL lookup
  friend Vector operator+(Vector lhs,        // passing lhs by value helps optimize chained a+b+c
                     const Vector& rhs) // otherwise, both parameters may be const references
  {
    lhs += rhs; // reuse compound assignment
    return lhs; // return the result by value (uses move constructor)
  }
};
 
Last edited:
  • Like
Likes FactChecker
  • #7
I can't help but to express how I feel. I am learning C++, I don't judge, also more importantly, if I need to read other people's program, I have to know all these. BUT, if I am writing my program, I would avoid using a lot of these "more elegant" way to save a line or two. Now that I almost finish the brief version of Gaddis book, the main thing I notice the difference of the modern language like C++ compare to what I learn 40 years ago is just more "elegant" ways to try to make the code more "natural", just to shorten a few lines. To me, I would much rather use x = x + 1 over x++ or ++x. I can put x = x + 1 to the place I want it to increment instead of the fancier prefix or postfix.

To me, when I write my own program, I would AVOID all these overload if all possible and just go back to the basic of c.x = a.x + b.x to add member data of the objects a and b. If I want to compare, I would just a.x < b.x individually.

I can't wait to finish this chapter, then to Polymorphism and Inheritance. Then to template and library and finish up C++. That should complete the basic C++, then likely move on. It's very different than I imagine before I started learning C++. To be very blunt, looking at all the things I have with the "latest and greatest" hardware, I serious question the software are better. If it is better, it sure does, NOT show with the slowness and intermittence from ALL the latest and greatest stuffs. I think I already named things I have here that suck to holly hell already. The latest is Direct TV upgraded my receivers and that stupid remote is just suck to holly hell. I KNOW how to use the remote very well, it's just the slowness, unreliable that really kills me. All the fancy features doesn't make up the flaws. Emphasize, I know how to use the remote, that's not the issue.
 
  • #8
@pbuk, you have a bug in your code.
C++:
Vector& operator+=(const Vector& rhs) // compound assignment (does not need to be a member,
  {                           // but often is, to modify the private members)
    *this.x += rhs.x;
    *this.y += rhs.y;
    return *this; // return the result by reference
  }
The member selection operator -- . -- is higher precedence that the dereference operator, *, which you probably know, but it may have slipped your mind. The first assignment above evaluates as if the left hand expression were *(this.x). Same problem with the second statement.

What is needed are parentheses to force the dereference to happen before the member select operation; i.e., (*this).x or better yet, this -> x.
 
Last edited:
  • #9
I rest my case.
 
  • #10
yungman said:
Now that I almost finish the brief version of Gaddis book, the main thing I notice the difference of the modern language like C++ compare to what I learn 40 years ago is just more "elegant" ways to try to make the code more "natural", just to shorten a few lines.
What language were you using in 1980, which is 40 years ago? Fortran? Pascal?
It's unrealistic to state that the changes made since those days are merely "elegant" attempts to make the code more natural, let alone just to shorten a few lines. Try rewriting the C++ programs you've written in Fortran 77, which was still fairly new in 1980. Good luck with that.
Or try doing the stuff you've been doing with classes, but using Pascal instead. And you'll have a hard time (meaning an impossible time) trying to implement polymorphism in Pascal, a subject you'll be coming up on soon.
yungman said:
To me, I would much rather use x = x + 1 over x++ or ++x. I can put x = x + 1 to the place I want it to increment instead of the fancier prefix or postfix.
Then you're fine with slower code. A statement like x = x + 1; has to evaluate x twice, while the increment variants only do so once. In fact, the increment and decrement operators are generally going to translate into a single assembly instruction, while your version could take several more operations if the compiler isn't very smart.
yungman said:
To me, when I write my own program, I would AVOID all these overload if all possible and just go back to the basic of c.x = a.x + b.x to add member data of the objects a and b.
So how would you output the data members of a class? Having an overloaded stream insertion operator would save a lot of lines of code.
yungman said:
To be very blunt, looking at all the things I have with the "latest and greatest" hardware, I serious question the software are better.
What do problems you have with the DirectTV receive and remote have to do with learning C++? And what do the "features" of these devices have to do with the capabilities of C++? Anybody can write bad code or bad firmware, or design crappy hardware, but does that mean the underlying programming language is no good?

You're comparing apples and oranges with a comparison between the features of a programming language and a hardware/firmware combination as implemented by DirectTV. This is not a reasonable comparison.
 
Last edited:
  • Like
Likes Vanadium 50
  • #11
What happen to my last post? Got deleted?
 
  • #12
@yungman, I deleted your last two posts, as being off-topic. Your complaints about a washing machine,, printer, newer car, and DirectTV have nothing to do with the topic of this thread, which I'll remind you is about operator overloading.
 
  • Like
Likes Vanadium 50
  • #13
Mark44 said:
It's unrealistic to state that the changes made since those days are merely "elegant" attempts to make the code more natural, let alone just to shorten a few lines. Try rewriting the C++ programs you've written in Fortran 77, which was still fairly new in 1980. Good luck with that.

Fortran 77? Bah! No need for them new-fangled features. Strings? Why good old Hollerith data works just fine! DO statements? I tell ya, any of them fancy-schmancy control structures can be implemented with good, old-fashioned GOTO's! 'Specially those computed GOTOs. And comment lines? Waste of a perfectly good punch card. Fiddlesticks!
 
  • Like
  • Wow
Likes jbriggs444, hmmm27 and pbuk
  • #14
Vanadium 50 said:
I tell ya, any of them fancy-schmancy control structures can be implemented with good, old-fashioned GOTO's!
And arithmetic IF's.
 
  • Like
Likes jbriggs444
  • #15
Vanadium 50 said:
Fortran 77? Bah!
I don't need no fancy schmancy high-level programming language like Fortran 77 or even Fortran 66. Writing plain old machine code is good enough for me.
dilbert_binary.gif


Dilbert, Sept 8, 1992
 
  • Haha
Likes Vanadium 50
  • #16
Mark44 said:
What is needed are parentheses to force the dereference to happen before the member select operation; i.e., (*this).x or better yet, this -> x.
Good catch, thanks.

I hardly ever post untested code but didn't have a compiler to hand so took the chance - I won't do that again. Edit: I was distracted by the comment in the boilerplate code I linked /* addition of rhs to *this takes place here */, but that's not much of an excuse :sorry:Well probably not.
 
  • #17
Vanadium 50 said:
'Specially those computed GOTOs.
OMG I had forgotten computed GOTOs - it's bedtime here and now I'm going to have nightmares!
 
  • #18
pbuk said:
I hardly ever post untested code but didn't have a compiler to hand so took the chance
Happens to the best of us ...
 
  • #19
Nightmares...indirection...
Z80:
        LD      C,A
        XOR     A
        LD      B,A
        LD      HL,JMPTABLE
        ADD     HL,BC
        JP     (HL)
...zzz...
 
  • #20
yungman said:
if I am writing my program, I would avoid using a lot of these "more elegant" way to save a line or two.
That is the wrong conclusion. The goal of these features are almost always to make the code easier to understand and maintain.
rather use x = x + 1 over x++ or ++x. I can put x = x + 1 to the place I want it to increment instead of the fancier prefix or postfix.
It is not that simple. It is enough, for now, that you know about these alternatives. That will allow you to recognize them and to use them when the circumstances make them desirable. I could give you examples, but you would probably not appreciate them until you see them for yourself.
To me, when I write my own program, I would AVOID all these overload if all possible and just go back to the basic of c.x = a.x + b.x to add member data of the objects a and b. If I want to compare, I would just a.x < b.x individually.
Just wait until you have to choose between hundreds (maybe thousands) of tedious, repetitive, hard to maintain (and error-prone) lines of code versus one simple line.
I can't wait to finish this chapter, then to Polymorphism and Inheritance. Then to template and library and finish up C++. That should complete the basic C++, then likely move on. It's very different than I imagine before I started learning C++. To be very blunt, looking at all the things I have with the "latest and greatest" hardware, I serious question the software are better.
You may not believe it now, but these languages were not developed just for fun. They addressed serious limitations in the prior languages.
 
  • Like
Likes Mark44 and Vanadium 50
  • #21
pbuk said:
OMG I had forgotten computed GOTOs - it's bedtime here and now I'm going to have nightmares!

Oh, there be worse...far worse...

Fortran:
   IF(J.EQ.0) ASSIGN 10 TO I
    ...
   GO TO I
   ...
10 CONTINUE

And if that weren't bad enough...

According to the standard, if an integer variable is used in ASSIGN, it can not be used in mathematical expressions. But not every compiler enforced this. They would let you write code like GO TO 2*I+10. Hilarity would ensue.
 
  • #22
C++ was never advertised as the most fun language to learn. Years ago, programmers were asked what they did for fun and a lot of them answered that they wrote Perl programs. Today, that distinction probably goes to Python. Perl is more targeted toward writing quick and "tolerant" code. Python is more strict, but it is the "hot" thing these days as the favorite fun language. Serious programmers often use Python when they have a choice.
 
Last edited:
  • #23
Mark44 said:
A statement like x = x + 1; has to evaluate x twice, while the increment variants only do so once. In fact, the increment and decrement operators are generally going to translate into a single assembly instruction, while your version could take several more operations if the compiler isn't very smart.

It is certainly true that the reason ++ was originally included in C was performance. But today? Modern compilers can certainly recognize i = 1 + i and generate code that uses an INCrement rather than an ADDition opcode. I would say that today it's an idiom of the language. Like contractions in English.

And, like contractions, nobody is forcing you to use them. But people will think it strange if you don't.

It also implies that one is not just adding one; one is counting.

C:
switch(n) {
   case 1:
      i += 12
   case 2:
      i += 24
   case 3:
      ++i;
  default:
      i += 36

}

is perfectly valid code, but most people would write ++i as i+=1, unless this was inside a loop and in the other cases 12, 24 or 36 elements would be skipped.
 
  • Love
Likes harborsparrow
  • #24
One place to use the i++ syntax is where you want to make sure that the variable, i, is incremented immediately after it is used and the incrementation can not be delayed or separated from that use:
C++:
this_value = x(i++);

Alternatives like:
C++:
this_value = x(i);
i=i+1;
can get accidentally split up.
 
Last edited:
  • Like
Likes Vanadium 50 and Mark44
  • #25
FactChecker said:
C++ was never advertised as the most fun language to learn. Years ago, programmers were asked what they did for fun and a lot of them answered that they wrote Perl programs. Today, that distinction probably goes to Python. Perl is more targeted toward writing quick and "tolerant" code. Python is more strict, but it is the "hot" thing these days as the favorite fun language. Serious programmers often use Python when they have a choice.
I am thinking about learning HTML after completing 16 chapters of C++. I think that's enough. This is so dry it's not funny. Studying for 5 months and almost the whole book and have only one Directory program I wrote to show for, and still only run in cmd window. I really need something more fun, something with graphics, something that I can see result. I spent so much effort writing the directory program that actually is of some use real life, I loaded for my wife, the first thing she said was " I don't like how it display"! Hell, it's in cmd window! I already change to more pleasing background color and full screen rather than the tiny black screen!

I am not a serious programmer, hell I am not even a programmer! This is just like crossword puzzle for senior citizen like me.
 
  • #26
yungman said:
I am thinking about learning HTML after completing 16 chapters of C++. I think that's enough. This is so dry it's not funny. Studying for 5 months and almost the whole book and have only one Directory program I wrote to show for, and still only run in cmd window. I really need something more fun, something with graphics, something that I can see result. I spent so much effort writing the directory program that actually is of some use real life, I loaded for my wife, the first thing she said was " I don't like how it display"! Hell, it's in cmd window! I already change to more pleasing background color and full screen rather than the tiny black screen!

I am not a serious programmer, hell I am not even a programmer! This is just like crossword puzzle for senior citizen like me.
Long ago, I recommended the Python language to you (but for serious work programming, it is hard to argue with C++). Python opens the door to a lot of the hobby projects that people do. It has a large and enthusiastic user group and a lot of freely available packages for robotics, graphics, artificial intelligence, and other things.
 
  • Like
Likes yungman
  • #27
FactChecker said:
Long ago, I recommended the Python language to you (but for serious work programming, it is hard to argue with C++). Python opens the door to a lot of the hobby projects that people do. It has a large and enthusiastic user group and a lot of freely available packages for robotics, graphics, artificial intelligence, and other things.
I am only in exploration phase at this point, I am too busy on C++ to really go deep. I have not decided on HTML yet, just a thought. One thing good to learn Python is I got the Python for kids book for my little grand daughter and I am trying so hard to entice her to programming. Ha ha, I even loaded the VS into her computer when she was staying with us last week. It is not important for grandpa to learn programming, but I think this is career for the new generation. The whole thing that even started me on programming was because my grandson who's a CS major said he doesn't have enough motivation. So I said try if grandpa is nipping on his heal!

Do you have an estimate how long it will take to learn to be get in the door of HTML or in Python? For reference, I learn the Gaddis book from beginning to chapter 14 in 5 months I am just missing the last chapter 15 on Polymorphism and Inheritance.

Thanks
 
  • #28
yungman said:
Do you have an estimate how long it will take to learn to be get in the door of HTML or in Python?
I suggest that you search this forum for "learn python" and look at some of the threads. Also, there are many youtube videos that get to interesting applications quickly (in an hour). I would not recommend that you concentrate on HTML as a programming language unless you are primarily interested in designing web pages.
 
Last edited:
  • Like
Likes yungman
  • #29
Mark44 said:
What is needed are parentheses to force the dereference to happen before the member select operation; i.e., (*this).x or better yet, this -> x.
Or still better, simply x? (since this is in a member function and x is also a member)
 
  • Like
Likes pbuk
  • #30
jtbell said:
Or still better, simply x? (since this is in a member function and x is also a member)
Right. My comment was in relation to how this could be used, which is certainly not needed in a member function.
 
  • #31
I have a question about overloading << and >>. Below is my program.

The question is where is the correct way to put the body of the operator<<() and operator >>() codes.

I have seen both in the book and in videos they put the codes OUTSIDE of the class definition like in line 19 to 26 within the comment.

I tried putting inside the class Person in line 9-12 and line15 and it works. Is there a problem to put it inside the class declaration like in my program here?

C++:
#include <iostream>
#include <string>
using namespace std;

class Person {
    string name; int age;
public:
    Person() { name = "Alan"; age = 0; }
    friend ostream& operator <<(ostream& output, Person& p) {
        output << " For whatever it's worth " << endl;
        output << " my name is " << p.name << " and my age is " << p.age << "\n\n";
        return output;
    }
    friend istream& operator >>(istream& input, Person& p) {
        input >> p.name; input >> p.age; return input;
    }
};
/*
ostream& operator << (ostream& output, Person& p) {
    output << " For whatever it's worth " << endl;
    output << " my name is " << p.name << " and my age is " << p.age << "\n\n";
    return output;
}
istream& operator >>(istream& input, Person& p) {
    input >> p.name; input >> p.age; return input;
}
*/
int main()
{
    cout << " Enter the name and age  " << endl;
    Person per;
    cin >> per;
    cout << per << "\n\n";
    return 0;
}

Thanks
 
  • #32
jtbell said:
Or still better, simply x? (since this is in a member function and x is also a member)
Yes of course, corrected, thanks.
 
  • #33
The last couple of days I've been having fun reviewing operator overloading by writing a class for 3D (x, y, z) vectors. The class ThreeVector has a static data member, incremented in the constructors, that counts how many vectors have been created. Each ThreeVector instance has a data member that contains a serial number, assigned in the constructors.

Each constructor, destructor, and arithmetic operator displays a comment beginning with "-- " to show the details of what's happening.

The code for the class is pretty long, and not completely polished yet anyway, but here's a main() function and the output it produces.

C++:
int main ()
{
    ThreeVector a(0, 0, -10), r0(0, 0, 0), v0(70, 0, 70);
    cout << "Acceleration = " << a << endl;
    cout << "Initial position = " << r0 << endl;
    cout << "Initial velocity = " << v0 << endl;
    double t = 5;
    cout << "At time = " << t << "..." << endl;
    ThreeVector r = r0 + v0 * t + 0.5 * a * t*t;
    cout << "Final position = " << r << endl;
    ThreeVector v = v0 + a * t;
    cout << "Final velocity = " << v << endl;
    return 0;
}
Code:
-- Constructed vector #1 containing (0, 0, -10).
-- Constructed vector #2 containing (0, 0, 0).
-- Constructed vector #3 containing (70, 0, 70).
Acceleration = (0, 0, -10)
Initial position = (0, 0, 0)
Initial velocity = (70, 0, 70)
At time = 5...
-- Copy-constructed vector #4 containing (70, 0, 70).
-- (70, 0, 70) * 5 gives (350, 0, 350).
-- Default-constructed vector #5.
-- Added (0, 0, 0) and (350, 0, 350) giving (350, 0, 350).
-- Copy-constructed vector #6 containing (0, 0, -10).
-- (0, 0, -10) * 0.5 gives (0, 0, -5).
-- Copy-constructed vector #7 containing (0, 0, -5).
-- (0, 0, -5) * 5 gives (0, 0, -25).
-- Copy-constructed vector #8 containing (0, 0, -25).
-- (0, 0, -25) * 5 gives (0, 0, -125).
-- Default-constructed vector #9.
-- Added (350, 0, 350) and (0, 0, -125) giving (350, 0, 225).
-- Destructed vector #8 containing (0, 0, -125).
-- Destructed vector #7 containing (0, 0, -25).
-- Destructed vector #6 containing (0, 0, -5).
-- Destructed vector #5 containing (350, 0, 350).
-- Destructed vector #4 containing (350, 0, 350).
Final position = (350, 0, 225)
-- Copy-constructed vector #10 containing (0, 0, -10).
-- (0, 0, -10) * 5 gives (0, 0, -50).
-- Default-constructed vector #11.
-- Added (70, 0, 70) and (0, 0, -50) giving (70, 0, 20).
-- Destructed vector #10 containing (0, 0, -50).
Final velocity = (70, 0, 20)
-- Destructed vector #11 containing (70, 0, 20).
-- Destructed vector #9 containing (350, 0, 225).
-- Destructed vector #3 containing (70, 0, 70).
-- Destructed vector #2 containing (0, 0, 0).
-- Destructed vector #1 containing (0, 0, -10).
 
  • #34
yungman said:
The question is where is the correct way to put the body of the operator<<() and operator >>() codes.

I have seen both in the book and in videos they put the codes OUTSIDE of the class definition like in line 19 to 26 within the comment.

I tried putting inside the class Person in line 9-12 and line15 and it works. Is there a problem to put it inside the class declaration like in my program here?
As far as your code is concerned, I think the two methods are equivalent. If the function body is outside the class definition, you still need to have a prototype (with the friend keyword) inside it, i.e. friend ostream& operator <<(ostream& output, Person& p); or more simply friend ostream& operator <<(ostream&, Person&);. Only the data types are necessary in this case.

You can also move the code for the member functions outside the class definitions, similarly, leaving only prototypes inside the class definition. In fact, this is how I prefer to do it. It allows one to compile the member functions separately, into a separate object-code file. One can then link the compiled object-code file to different programs without having to re-compile the class member functions each time.
 
  • Like
Likes yungman
  • #35
Anyone can answer my post 31?
 

Similar threads

Replies
23
Views
2K
Replies
4
Views
1K
Replies
5
Views
2K
Replies
4
Views
1K
Replies
30
Views
5K
Replies
4
Views
2K
Replies
2
Views
1K
Replies
15
Views
2K
Back
Top