Any way to overload [ ] for vector of structure?

In summary, the author attempted to overload [] on vector of structure, but failed. They provide a working example of a class that overloads [] and provides a more detailed explanation of what is going wrong.
  • #36
Filip Larsen said:
Hint:

I see you tried this once too. :smile:
 
Technology news on Phys.org
  • #37
Filip Larsen said:
Line 9 (of your commented code block): the constructor notation : x(x), y(y), z(z) is member initialization, so the member variable x is initialized with the formal constructor parameter x. This means the matched member constructor is called. If you do as on (your) line 10 then the members are first default constructed (which for doubles means not initialized) and then they are assigned a value. If you are confused about the repeated name, then note constructor in line 9 could also be written as, say, vec3(double xi = 0, double yi = 0, double zi = 0) : x(xi), y(yi), z(zi) {}.

Line 21 defines three vec3 instances, r0, v0 and a, and uses constructor arguments to initialize their x, y, z member with values. If the construct arguments had been left out the coordinates would have been initialized to 0 due to the default values in the constructor. The values themselves are written as integers, but C++ will implicit convert these values to doubles when matching which constructor to use.

Line 23: Not sure what your question is, but r is defined and initialized with the result of the calculation.
Thanks
Yes, I understand the Line 9 correctly,

I read Line 21 wrong, I though r0, v0 and a are integers multiplying into the given values. and use line 21 to solve the value of r0, v0 and a first. That's why I thought it's a single value.
 
  • #38
Mark44 said:
You're missing a couple of important points here.
First, the work of writing an overloaded operator happens once, but once done, it can be used many times. When you overload an operator, you are in essence extending the language, allowing it do some operation that isn't part of the language definition.
Second, the overloaded operator doesn't just make things look better - they allow code that uses the operator to be more natural, with the potential benefit of code that is less prone to errors. For example, if AddrBkA and AddBkB are directories, having an overloaded operator+() could allow a user to write AddrBkA + AddrBkB as an expression that would merge two address books.
Another point that you're missing is that their are hierarchies of programmers. At the lowest level are programmers who use existing libraries to create applications. At a higher level are those who create libraries and classes that others can use. In your case you have been wearing both hats, so the distinction isn't clear: the application developer who writes main(), and the class designer/implementer.
Not at all. And you have seen numerous examples in this thread.
No, this is not so. Already pointed out - the overloaded operator+() in the example allows the program to calculate ##\vec v = \vec a + \vec b##. What is returned is a vector. You apparently missed that the result object r was declared to be of type Vec3.
For the example shown it would also have been convenient to overload the * operator, to allow multiplication of a Vec3 object by a scalar. (In the assignment statement above, t and 0.5 are scalars, floating point numbers in this case.)
No I am not confused, my first read (very late last night) was thinking and actually asked to confirm whether r0, v0 and a are integers to multiply into the initial values given into line 21. And no, it's not that I don't understand operator+(). I never learn using this as vector addition before. I just BARELY learn this about a week or so ago, with one example in the book that it's not even worth putting in the notes. The only one that mean something is Jtbell's example which is a whole hell of a lot simpler than this. That's why I kept wanting to venture out to do extra rather just follow the book. It's very discouraging to hear this from you.
 
Last edited:
  • #39
yungman said:
No I am not confused, my first read (very late last night) was thinking and actually asked to confirm whether r0, v0 and a are integers to multiply into the initial values given into line 21.
Here's what you wrote when asking about the code that Filip Larsen wrote:
yungman said:
C++:
int main()
{   
     // are r0, v0,a are numbers? what? integer or float?
     vec3 r0(1, 2, 3), v0(2, 3, 4), a(1, 1, 1); //declare 3 object of vec3?
It should have been obvious that r0, v0, and a are all objects of the vec3 class, and that all three of these objects are being created and initialized as shown by the argument lists.
So if you can't tell that r0, v0, and a are vec3 objects, and think that they might be of type int or float or whatever, then, I would say that you are not clear on variable declarations, one of the first topics Gaddis talks about.
yungman said:
And no, it's not that I don't understand operator+(). I never learn using this as vector addition before.
I don't know what you mean by "I never learn using this as vector addition before."
jtbell's example program was all about vectors, with several overloaded operators. I provided another example based on jtbell's code. Filip Larsen just posted another example in post #23, with the main difference being that it defined a struct rather than a class.
 
  • Like
Likes Vanadium 50
  • #40
I was looking at Jtbell's program as class object with 3 arguments, never think of it as vector.

Remember, when I do programming on these overload, I still have to read my notes to see the syntax, it's not like I can just remember all the stuffs as they are so new to me. Just barely keeping up. I just read it wrong that those are numbers late at night and want to confirm that.

I still have problem digesting this function mean the right side or what. You are a professor, you really think your student can really get all these when you first teach them? They might be quiet and not asking question, you really think they actually understand and remember all that right away? believe me, if I take any class, I will get A's from my track record, able to do the exam and really understand and remember is two different stories. The last class I took was ODE in a community college, one time before the class, we started talking about the material, I was so surprise how much those students that got A's didn't get.

Actually now that I realize r0, v0 and a are objects of vec3, the problem actually look a lot easier.
 
  • #41
Actually I looked at the program again, it's actually not hard at all, just 3 terms add together, only one new one is: vec3 operator*(double k, const vec3& rhs) { return rhs * k; }

I only saw with one parameter only like vec3 operator*(double k) const { return { k * x, k * y, k * z }; }

That tells me don't look at things after 2am in the morning, for whatever reason I thought about matrix multiplication! And I thought what a hard problem! Don't know what I was thinking.
 
  • #42
yungman said:
I was looking at Jtbell's program as class object with 3 arguments, never think of it as vector.
I assume you mean his program in your other thread about operator overloads. This is one of the lines in his program:
C++:
ThreeVector a(0, 0, -10), r0(0, 0, 0), v0(70, 0, 70);
The name of the class should have been a clue that he was working with vectors, and specifically vectors with three components.
yungman said:
You are a professor, you really think your student can really get all these when you first teach them? They might be quiet and not asking question, you really think they actually understand and remember all that right away?
Some of them get it right away, and some don't. I always encourage them to ask questions, but I also encourage them to do the reading as well.
 
  • Like
Likes Vanadium 50
  • #43
Filip Larsen said:
You have seen at least one example before :wink:. Let me make a fresh small example:

C++:
// C++ 17
#include <iostream>

using namespace std;

struct vec3 {
    double x, y, z;
    vec3(double x = 0, double y = 0, double z = 0) : x(x), y(y), z(z) {}
    vec3 operator+(const vec3& rhs) const { return { x+rhs.x, y+rhs.y, z+rhs.z }; }
    vec3 operator*(double k) const { return { k*x, k*y, k*z }; }
};

vec3 operator*(double k, const vec3& rhs) { return rhs*k; }
ostream& operator<<(ostream& os, const vec3& v) { return os << "(" << v.x << " " << v.y << " " << v.z << ")"; }int main()
{
    vec3 r0(1, 2, 3), v0(2, 3, 4), a(1, 1, 1);
    double t = 2.0;
    vec3 r = r0 + t*v0 + 0.5 * a * t * t;
    cout << "r = " << r << endl;

    return 0;
}
I never learn line 13, I only learn operator*() of line 10 with single parameter. My question is what is line 13?

At a glance, line 13 is like an overloading that call line10 to do the detail multiplication. It's like overloading on an overloading, or a cascade overloading.
 
  • #44
yungman said:
My question is what is line 13?

When you overload an operator, say multiply like on line 10, inside a class, the left hand side argument is an instance of the class in question, i.e. this. This means the compiler will parse expressions like "(vec3 instance expression) * (double value expression)" using this operator overload.

But what if I would like to write "(double value expression) * (vec3 instance expression)"? Luckily, I can also overload operators outside any class by providing both left and right hand side formal parameters. Thus, the definition in line 13 makes is possible to multiply a double with a vec3.

You have actually seen this before, because when overloading << to output content of a class, you also have to do that outside your class since left hand side is an std::ostream reference.

It is perhaps tempting to ask why not define all operator overloads outside classes? That is indeed possible and is a nice pattern provided the overloaded methods only need public access to class. If it needs to access private (or protected) members then it probably need to forward the call to a member method anyway, or, as a frowned-upon alternative, use a friend declaration.

A good pattern I recommend for more complete classes (i.e. not quick-and-dirty minimum code), is to write all operator logic as normal methods (can be virtual too, if needed) and then define the operator overloads outside the class using only those methods. For example

C++:
class vec3 {
public:
    vec3 multiply(const vec3& rhs);
};

vec3 operator*(const vec3& lhs, const double rhs) { return lhs.multiply(rhs); }
vec3 operator*(const double lhs, const vec3& rhs) { return rhs.multiply(lhs); }
 
  • Like
Likes yungman
  • #45
Thanks Filip
I figure later line 13 cannot be put inside the struct or class as it cannot have the left side as k. I actually when quite far eliminating line 13 by rearranged the numbers ( like 0.5*t*t) onto the left side of the object and I can eliminate line 13 and make it uses line 10.

But I think you can use ostream& operator<<(ostream& os, const vec3& v) { return os << "(" << v.x << " " << v.y << " " << v.z << ")"; } inside the class.

Can you tell me what is the name of the function type in line 13, I want to read up more on overloading function that can only be outside of the class. I never learn that yet and it's not in the book.

This is what I am working on, I added a lot of stuffs mainly putting in the name and I traced step by step of the program. I yet to manage to output r yet. I do get the correct answer( using only line 10 in your program).

C++:
#include <iostream>
#include <cstring>
using namespace std;
const int Nsize = 51;  
char Add[Nsize] = "temp0", Multi1[Nsize] = "mul10", Multi2[Nsize] = "mul20";
class vec3 {
private: double x, y, z;  char name[Nsize]; 
public:

    vec3(const char *desc, double x = 0, double y = 0, double z = 0) :  x(x), y(y), z(z)
    {strncpy_s(name, Nsize, desc, Nsize);
     cout << "[Con] for " << (*this).name << "(" << this->x << 
         ", " << this->y << ", " << this->z << ")\n\n";
    }
   /* vec3(vec3& obj)
    { strncpy_s(name, Nsize, "Cpycon", Nsize);
    this->x = obj.x; this->y = obj.y; this->z = obj.z;
      cout << "[CopyC]" << name << "(" << x << ", " << y << ", " << z << 
       " copied from" << obj.name<<"(" << obj.x << ", " << obj.y << ", " << obj.z << ")\n\n";
    }*/
    vec3 operator+(const vec3& rhs) 
    {   vec3 sum(name, 0, 0, 0);
        strncpy_s(sum.name, Nsize, Add, Nsize);
        Add[4]++;
        sum.x = x + rhs.x; sum.y = y + rhs.y; sum.z = z + rhs.z;
        cout << " [Op+] for " << this->name << "(" << this->x << 
            ", " << this->y << ", " << this->z << ")\n\n";
        return (sum ); }
    vec3 operator*(double k) const
    {   vec3 mul1(name, 0, 0, 0);
        strncpy_s(mul1.name, Nsize, Multi1, Nsize);
        Multi1[4]++;
        mul1.x = k * x; mul1.y = k * y; mul1.z = k * z;
        cout << " [Op1*] for " << this->name << "(" << this->x <<
            ", " << this->y << ", " << this->z << ")\n\n";
        return mul1; }
};

/*vec3 operator*(double k, const vec3& rhs)
{ return rhs * k; }
    vec3 operator*(double k, const vec3& rhs)
        {   vec3 mul2(char name[Nsize], 0, 0, 0);
            strncpy_s(mul2.name, Nsize, Multi2, Nsize);
            Multi1[4]++;
            mul2.x = k * x; mul2.y = k * y; mul2.z = k * z;
            cout << " [Op1*] for " << this->name << "(" << this->x <<
                ", " << this->y << ", " << this->z << ")\n\n";
            return mul2; }*/

/*ostream& operator<<(ostream& os, const vec3& v)
{ return os << "(" << v.name << v.x << " " << v.y << " " << v.z << ")"; }*/int main()
{    double t = 2.0;
    vec3 r0("r0", 1, 2, 3), 
         v0("v0", 2, 3, 4), 
         a("a", 1, 1, 1);

    vec3 r = r0 +
          v0*t + 
       a * ( t * t * 0.5)
        ;

    //cout << "r = " << r << endl;

    return 0;
}
I am having fun with this program, learning extra things the book not even comes close to.
Thanks
 
  • #46
yungman said:
But I think you can use ostream& operator<<(ostream& os, const vec3& v) { return os << "(" << v.x << " " << v.y << " " << v.z << ")"; } inside the class.

Can you tell me what is the name of the function type in line 13, I want to read up more on overloading function that can only be outside of the class.

You can (as far as I know) only put in a full binary operator overload (i.e. one with explicit left and right hand arguments) if you make it friend (which I guess is a slightly better way to use friend, i.e. the function definition stays inside the class it befriends). I encourage you to look at some more examples on https://en.cppreference.com/w/cpp/language/operators, specifically the section "Binary arithmetic operators" around mid-page. For convenience let me quote that particular example here:
https://en.cppreference.com/w/cpp/language/operators said:
Binary operators are typically implemented as non-members to maintain symmetry (for example, when adding a complex number and an integer, if operator+ is a member function of the complex type, then only complex+integer would compile, and not integer+complex). Since for every binary arithmetic operator there exists a corresponding compound assignment operator, canonical forms of binary operators are implemented in terms of their compound assignments:

C++:
class X
{
 public:
  X& operator+=(const X& rhs) // compound assignment (does not need to be a member,
  {                           // but often is, to modify the private members)
    /* addition of rhs to *this takes place here */
    return *this; // return the result by reference
  }
 
  // friends defined inside class body are inline and are hidden from non-ADL lookup
  friend X operator+(X lhs,        // passing lhs by value helps optimize chained a+b+c
                     const X& rhs) // otherwise, both parameters may be const references
  {
    lhs += rhs; // reuse compound assignment
    return lhs; // return the result by value (uses move constructor)
  }
};

As to the language construct name, I would guess it can be called "a non-member operator overload declaration/definition".
 
  • Like
Likes yungman
  • #47
Thanks Filip, I have been reading binary operator overloading with two explicit arguments ( L and R). I want to make a correction, the streaming operator overloading has to be "friend" to stay inside the class. I forgot about that. I am actually working on your example, BUT I am adding the c-string name to pass around. I put the operator*() with two argument INSIDE the class to declare as friend.

I run into one error before I can complete it. Here is the code:
C++:
#include <iostream>
#include <cstring>
using namespace std;
const int Nsize = 51;  
char Add[Nsize] = "temp0", Multi1[Nsize] = "mul10", Multi2[Nsize] = "mul20";
class vec3 {
private: char name[Nsize]; double x, y, z;  
public:

    vec3(const char *desc, double x = 0, double y = 0, double z = 0) :  x(x), y(y), z(z)
    {strncpy_s(name, Nsize, desc, Nsize);
     cout << "[Con] for " << (*this).name << "(" << this->x << 
         ", " << this->y << ", " << this->z << ")\n\n";
    }
   /* vec3(vec3& obj)
    { strncpy_s(name, Nsize, "Cpycon", Nsize);
    this->x = obj.x; this->y = obj.y; this->z = obj.z;
      cout << "[CopyC]" << name << "(" << x << ", " << y << ", " << z << 
       " copied from" << obj.name<<"(" << obj.x << ", " << obj.y << ", " << obj.z << ")\n\n";
    }*/
    vec3 operator+(const vec3& rhs) 
    {   vec3 sum(name, 0, 0, 0);
        strncpy_s(sum.name, Nsize, Add, Nsize);
        Add[4]++;
        sum.x = x + rhs.x; sum.y = y + rhs.y; sum.z = z + rhs.z;
        cout << " [Op+] for " << this->name << "(" << this->x << 
            ", " << this->y << ", " << this->z << ")\n\n";
        return (sum ); }
    vec3 operator*(double k) const
    {   vec3 mul1(name, 0, 0, 0);
        strncpy_s(mul1.name, Nsize, Multi1, Nsize);
        Multi1[4]++;
        mul1.x = k * x; mul1.y = k * y; mul1.z = k * z;
        cout << " [Op1*] for " << this->name << "(" << this->x <<
            ", " << this->y << ", " << this->z << ")\n\n";
        return mul1; }
   // friend vec3 operator*(double k, const vec3& rhs)
      //{ return rhs * k; }
        friend vec3 operator*(double k, const vec3& rhs) 
            {   vec3 mul2(name, 0, 0, 0);
                strncpy_s(mul2.name, Nsize, Multi2, Nsize);
                Multi2[4]++;
                mul2.x = k * rhs.x; mul2.y = k * rhs.y; mul2.z = k * rhs.z;
                cout << " [Op1*] for " << mul2.name << "(" << mul2.x <<
                    ", " << mul2.y << ", " << mul2.z << ")\n\n";
                return mul2; }
        friend ostream& operator<<(ostream& os, const vec3& v)
           { return os << "(" << v.name << v.x << " " << v.y << " " << v.z << ")"; }
};
I got an error in line 40 and the message is:
Error.jpg

I don't know how to fix it. I have exactly the same in line 30, and it works. Can you help?

Thanks
 
  • #48
I am really confused, I changed line 40 from name to "mul2", it works. I really don't understand. Why line 30 works with name, but the friend operator will not work?
C++:
#include <iostream>
#include <cstring>
using namespace std;
const int Nsize = 51;  
char Add[Nsize] = "temp0", Multi1[Nsize] = "mul10", Multi2[Nsize] = "mul20";
class vec3 {
private: 
public:
    char name[Nsize]; double x, y, z;  
    vec3(const char *desc, double x = 0, double y = 0, double z = 0) :  x(x), y(y), z(z)
    {strncpy_s(name, Nsize, desc, Nsize);
     cout << "[Con] for " << (*this).name << "(" << this->x << 
         ", " << this->y << ", " << this->z << ")\n\n";
    }
    vec3(const vec3& obj)
    { strncpy_s(name, Nsize, "Cpycon", Nsize);
    x = obj.x; y = obj.y; z = obj.z;
      cout << "[CopyC]" << name << "(" << x << ", " << y << ", " << z << ")  copied from  " 
       << obj.name<<"(" << obj.x << ", " << obj.y << ", " << obj.z << ")\n\n";
    }
    vec3 operator+(const vec3& rhs) 
    {   vec3 sum(name, 0, 0, 0);
        strncpy_s(sum.name, Nsize, Add, Nsize);
        Add[4]++;
        sum.x = x + rhs.x; sum.y = y + rhs.y; sum.z = z + rhs.z;
        cout << " [Op+] for " << this->name << "(" << this->x << 
            ", " << this->y << ", " << this->z << ")\n\n";
        return (sum ); }
    vec3 operator*(double k) const
    {   vec3 mul1(name, 0, 0, 0);
        strncpy_s(mul1.name, Nsize, Multi1, Nsize);
        Multi1[4]++;
        mul1.x = k * x; mul1.y = k * y; mul1.z = k * z;
        cout << " [Op1*] for " << this->name << "(" << this->x <<
            ", " << this->y << ", " << this->z << ")\n\n";
        return mul1; }
   // friend vec3 operator*(double k, const vec3& rhs)
      //{ return rhs * k; }
        friend vec3 operator*(const double k, const vec3& rhs) 
            {   vec3 mul2("mul2", 0, 0, 0);
                strncpy_s(mul2.name, Nsize, Multi2, Nsize);
                Multi2[4]++;
                mul2.x = k * rhs.x; mul2.y = k * rhs.y; mul2.z = k * rhs.z;
                cout << " [Op1*] for " << mul2.name << "(" << mul2.x <<
                    ", " << mul2.y << ", " << mul2.z << ")\n\n";
                return mul2; }
        friend ostream& operator<<(ostream& os, const vec3& v)
           { return os << " " << v.name <<"(" << v.x << " " << v.y << " " << v.z << ")"; }
};
int main()
{    double t = 2.0;
    vec3 r0("r0", 1, 2, 3), 
         v0("v0", 2, 3, 4), 
         a("a", 1, 1, 1);

    vec3 r = r0 +
          t*v0 + 
       ( t * t * 0.5)* a 
        ;
    cout << "r = " << r << endl;

    return 0;
}
}

This C++ is really frustrating. Seems it's a lot easier to work with numbers, but when comes to class with c-strings, it's a lot more difficult. That's why I keep working on this. I even completed program of complex number multiplication using operator*() with two explicit argument, no problem at all as long as I don't add in the c-string for names.

Please help.

Thanks
 
Last edited:
  • #49
yungman said:
I am really confused, I changed line 40 from name to "mul2", it works. I really don't understand. Why line 30 works with name, but the friend operator will not work?

You are getting the error in line 40 because that friend function is not a member function, but more like a static function, and for those there are no this defined. Defining a friend function textually inside a class definition does no in itself mean its a member function; it means just the same as if the friend function was defined outside the lexical scope of the class. Also, contrast this with the member function you define in line 30 which do have a this defined, so name there implicitly refers to this->name.

As a minimal fix closest to your original intent I will suggest you just use rhs.name in line 40, or, since you overwrite mul2.name with Multi2 on the next line anyway, just use Multi2 in line 40 and skip the string copy. But if you get into more trouble fumbling around with those damn c-string you know what I am going to say :wink:.
 
  • Like
Likes yungman
  • #50
Filip Larsen said:
You are getting the error in line 40 because that friend function is not a member function, but more like a static function, and for those there are no this defined. Defining a friend function textually inside a class definition does no in itself mean its a member function; it means just the same as if the friend function was defined outside the lexical scope of the class. Also, contrast this with the member function you define in line 30 which do have a this defined, so name there implicitly refers to this->name.

As a minimal fix closest to your original intent I will suggest you just use rhs.name in line 40, or, since you overwrite mul2.name with Multi2 on the next line anyway, just use Multi2 in line 40 and skip the string copy. But if you get into more trouble fumbling around with those damn c-string you know what I am going to say :wink:.
Thanks

I actually have no problem with your original program, after I think straight the next morning, it's actually quite easy to understand, just the operator*() with two explicit arguments that I learn after you gave me the information. I always have problem copying c-string back and fore in Copy Constructor and all that. That's the reason I keep practice that over and over.
At the mean time while I was stuck in this, I actually work on the Complex number multiplication and addition. I got that done really quick as I don't have c-string( intentionally not having that as I want to practice on binary operator with two explicit arguments). I wrote a void result() to make the complex number looks better when the Imaginary part is -ve. here is the program, it works:
C++:
#include <iostream>
using namespace std;
class Complex
{  public:
      double r, i;
      Complex(double r = 0, double i = 0):r(r), i(i) {};
      Complex operator+(const Complex& rhs)
      {      Complex sum;
          sum.r = this->r + rhs.r; sum.i = this->i + rhs.i;
          return sum;
      }
      friend Complex operator*(const Complex& left, const Complex& right)
      {    Complex mul;
        mul.r = left.r * right.r - left.i * right.i;
        mul.i = left.r * right.i + left.i * right.r;
        return mul;
      }
      void result(const Complex& obj)//Correct display format depends on sign of imaginary part.
      { if (obj.i >= 0){ cout << " (" << obj.r << " + " << obj.i << "j)\n\n";}
        else {  cout << " ("<<obj.r << " - " << abs(obj.i) << "j)\n\n"; }
      }     
};
int main()
{    Complex A, B, C;
    cout << " Enter the real part of A:      "; cin >> A.r;
    cout << " Enter the imaginary part of A: "; cin >> A.i;
    cout << " Enter the real part of B:      "; cin >>B.r;
    cout << " Enter the imaginary part of B: "; cin >> B.i; cout << endl;
    C = A * B;
    cout << " A X B ="; C.result(C);
    C = A + B;
    cout << " A + B ="; C.result(C);
    return 0;
}

Thanks for helping me, I think I am getting better with these overloading. I will work on what you suggested in this post.

Thank you very much.
 
  • #51
Filip Larsen said:
You are getting the error in line 40 because that friend function is not a member function, but more like a static function, and for those there are no this defined. Defining a friend function textually inside a class definition does no in itself mean its a member function; it means just the same as if the friend function was defined outside the lexical scope of the class. Also, contrast this with the member function you define in line 30 which do have a this defined, so name there implicitly refers to this->name.

As a minimal fix closest to your original intent I will suggest you just use rhs.name in line 40, or, since you overwrite mul2.name with Multi2 on the next line anyway, just use Multi2 in line 40 and skip the string copy. But if you get into more trouble fumbling around with those damn c-string you know what I am going to say :wink:.

I know you are right, I even try putting vec3 D(name, 0, 0, 0); inside main, it won't work. I tried using this->x inside the friend function and it doesn't work. So definitely what you said is true.

BUT I declare mul2 as object of Complex. Does it matter whether it's a member function or only a friend? I should be able to use the public member name[Nsize] for mul2. I still don't quite get what the reason.

Thanks
 
Last edited:
  • #52
yungman said:
BUT I declare mul2 as object of Complex. Does it matter whether it's a member function or only a friend?

(I assume you still refer to your vec3 class in post #48 and not your new Complex class from post #50.)

As I replied in post #49, the friend operator overload is really considered to be just a function and not a member function with an implied object context (i.e. this). The fact that it in this case is declared in the lexical scope of the class does not change anything. Consider the example
C++:
#include <iostream>

using namespace std;

class Thing {
    int m_a;   
    friend void f(Thing& t) {
        t.m_a = 3;
    }
public:
    int a() const { return m_a; }
};

int main()
{
    Thing t;
    f(t);
    cout << "t.a = " << t.a();
    return 0;
}
this is really understood by the compiler as
C++:
#include <iostream>

using namespace std;

class Thing {
    int m_a;    
    friend void f(Thing& t);
public:
    int a() const { return m_a; }
};

void f(Thing& t) {
    t.m_a = 3;
}

int main() {
    Thing t;
    f(t);
    cout << "t.a = " << t.a();
    return 0;
}
That is, the function f is considered to "be outside" the Thing class even though it (in first example above) is define lexically inside the Thing class.

Also, I can see in your new Complex class you have defined Complex operator*(const Complex& lhs, const Complex& rhs), but since the first parameter is a Complex the normal practice is to define it as the overloaded member function Complex operator*(const Complex& rhs) const where left hand side inside the implementation of that member function is represented by this. The friend operator* notation/idiom is only required when the left-hand argument is NOT of the type in question, e.g. in your case if you want to have an operator so you can write (double expression)*(Complex expression).

yungman said:
I should be able to use the public member name[Nsize] for mul2. I still don't quite get what the reason.

In the context of your original question relating to this, yes, you can refer to it as mul2.name.
 
  • Like
Likes yungman
  • #53
Filip Larsen said:
(I assume you still refer to your vec3 class in post #48 and not your new Complex class from post #50.)

As I replied in post #49, the friend operator overload is really considered to be just a function and not a member function with an implied object context (i.e. this). The fact that it in this case is declared in the lexical scope of the class does not change anything. Consider the example
C++:
#include <iostream>

using namespace std;

class Thing {
    int m_a;
    friend void f(Thing& t) {
        t.m_a = 3;
    }
public:
    int a() const { return m_a; }
};

int main()
{
    Thing t;
    f(t);
    cout << "t.a = " << t.a();
    return 0;
}
this is really understood by the compiler as
C++:
#include <iostream>

using namespace std;

class Thing {
    int m_a; 
    friend void f(Thing& t);
public:
    int a() const { return m_a; }
};

void f(Thing& t) {
    t.m_a = 3;
}

int main() {
    Thing t;
    f(t);
    cout << "t.a = " << t.a();
    return 0;
}
That is, the function f is considered to "be outside" the Thing class even though it (in first example above) is define lexically inside the Thing class.

Also, I can see in your new Complex class you have defined Complex operator*(const Complex& lhs, const Complex& rhs), but since the first parameter is a Complex the normal practice is to define it as the overloaded member function Complex operator*(const Complex& rhs) const where left hand side inside the implementation of that member function is represented by this. The friend operator* notation/idiom is only required when the left-hand argument is NOT of the type in question, e.g. in your case if you want to have an operator so you can write (double expression)*(Complex expression).
In the context of your original question relating to this, yes, you can refer to it as mul2.name.
Thanks so much Filip, I am going to read through chapter 13 and 14 on classes. Old brain needs to refresh the memory concentrating on member data access and all that. It's so easy to just follow the syntax and do things without really understanding them, that's why I want to keep writing stupid codes like those to keep going through them to see anything slipped through the cracks.

I see what you mean use two explicit argument is not necessary for L and R are the same class object. I just want to practice that. That's new. Book does not elaborate on the streaming overload using friend.

Many thanks.
 
  • Like
Likes Filip Larsen
Back
Top