Any way to overload [ ] for vector of structure?

  • Thread starter Thread starter yungman
  • Start date Start date
  • Tags Tags
    Structure Vector
AI Thread Summary
Overloading the `[]` operator for a vector of structures in C++ is possible, but the original code encounters issues due to incorrect initialization of the vector within the class. The vector should be declared without size in the class definition and initialized in the constructor, either by resizing it or using an initializer list. The operator overload must return an `int` type, matching the type of the data being accessed. Understanding the proper use of vector methods like `resize` and `at` is crucial for effective implementation. Properly addressing these points will enable successful operator overloading for the vector of structures.
yungman
Messages
5,741
Reaction score
294
I have been studying overloading [ ]. I understand how it works from the book. I experiment using vector of structure and obviously I can't make it work. I wonder if it is possible to overload [] on vector of structure. Here is what I have and it's not even close to working, what can I do to make this work?

C++:
#include <iostream>
#include <vector>
using namespace std;
class VecA 
{
private:
    struct Directory { char name[25]; int amount; };
    vector<Directory>Ivar(3); 
public:    
    VecA(int sub1, int sub2, int sub3) //constructor with 3 parameters of int
          {Ivar[0].amount = sub1; Ivar[1].amount = sub2; Ivar[2].amount = sub3;}
        int &operator[](int position){  return Ivar[position].amount;}
};
int main()
{    VecA anil(1, 2, 3);
    cout << anil[0] << ", " <<anil[1] << ", " << anil[2] << "\n\n";
    return 0;
}

In the code, I try to return Ivar[position].amount, it flagged me. In fact, it flagged me to put vector<Directory>Ivar(3) inside the class definition.

Is it possible to make this work?

Thanks
 
Last edited:
Technology news on Phys.org
What have you written as return type of your operator[] overload, and what are you actually returning? Hint: what you return have to match, or at least be implicit castable to the return type.

(The rest of your code also have some issues, but I understand if you want to focus on one issue at a time :wink:)
 
Filip Larsen said:
What have you written as return type of your operator[] overload, and what are you actually returning? Hint: they have to match.
I am trying to return an integer. How can I specify it's integer? I have to specify it's the structure Directory first in the statement.

Thanks
 
With the declaration "Directory operator[](int position)" what return type do this method has? If you want to return an int then what should you write instead? (This is a very basic method and return type thing, nothing fancy).
 
Filip Larsen said:
With the declaration "Directory operator[](int position)" what return type do this method has? If you want to return an int then what should you write instead? (This is a very basic method and return type thing, nothing fancy).
Thanks for the reply, I changed to int operator[](int position){return Ivar[position].amount}. still doesn't work.

Thanks
 
yungman said:
I changed to int operator[](int position){return Ivar[position].amount}. still doesn't work.

What doesn't work?

Perhaps you can find inspiration in the following working example:
C++:
//C++ 17
#include <iostream>
#include <vector>

using namespace std;

class DirectoryVector {
    struct Directory {
        string name;
        int amount;
    };
    vector<Directory> entries;
    
public:
    DirectoryVector(const vector<int>& initialAmounts) {
        entries.reserve(initialAmounts.size());
        for (auto &amount : initialAmounts) {
            entries.push_back({"", amount});
        }
    }

    int operator[](int index) const {
        return entries.at(index).amount;
    }
};

int main()
{
    DirectoryVector dv({ 1, 2, 3});
    cout << "dv[2] = " << dv[2];

    return 0;
}
 
  • Like
Likes yungman
Your original code for the operator,
C++:
int& operator[] (int position) { return Ivar[position].amount; }
works fine for me, after fixing your other error.

Your real problem is in trying to declare vector<Directory> Ivar(3); as a member of class VecA.

(Aside: When you have several compiler errors, it's always a good idea to tackle the first one first. Errors early in the code can trigger apparent errors in later code that's actually OK.)

I totally understand why you tried to do it this way. When you declare an array of three Directory's and a vector of three Directory's in the body of a function, you do this:
C++:
Directory ArrA[3];
vector<Directory> VecA(3);
It's natural to assume that because you declare an array same way in a class definition, you can do likewise with the vector. Unfortunately, that doesn't work, because the "declaration" of the vector above isn't a pure declaration. The "(3)" invokes a specific non-default constructor of class vector. In the context of a class definition, you have to do that in a constructor for that class.

Filip showed you one way. I'll show you a couple of other ways that might be easier to follow, but might have disadvantages in efficiency or whatever, compared to his method.

Both methods (and Filip's) declare the vector as simply vector<Directory> Ivar; i.e. as an "empty" vector with zero length to start with. Now let's focus on your constructor for VecA, which has to fix the size of the vector.

Method 1: resize the vector in the body of the VecA constructor:

Add the statement Ivar.resize(3); at the beginning of the constructor. I think you can do this yourself. This method uses the default vector constructor to create an empty vector, when the VecA constructor starts up; then resizes the vector to the desired size.

Method 2: Use the VecA constructor's initializer list:

C++:
    VecA(int sub1, int sub2, int sub3) : Ivar(3)
      { Ivar[0].amount = sub1; Ivar[1].amount = sub2; Ivar[2].amount = sub3; }
The initializer at the end of the first line invokes the appropriate vector constuctor on Ivar directly, before any of the code in the body of the VecA constructor is executed. This is a bit more efficient than the first method, because it sets up the vector in one step (construction) instead of two (construction and resizing).
 
Last edited:
  • Like
Likes yungman
jtbell said:
The "(3)" invokes a specific non-default constructor of class vector. In the context of a class definition, you have to do that in a constructor for that class.

Edit: In my first comment below I wrote vector<int> member {3}; as an example, but this does not work as intended since 3 is an int and thus seen as an initializer list of one element (the vector size will be 1 afterwards). In my comment I have changed to string so the {3} is parsed as a vector size argument (ref. (3) on https://en.cppreference.com/w/cpp/container/vector/vector). Another good reason to stay away from this vector constructor!

In modern C++ you can actually define a vector (member) variable like vector<string> member {3}; to get it initialized with 3 default-valued string if you really want. But in the present case it sure makes more sense to set the size in a constructor of the class containing the vector, just as you showed in post #9.

Also, yungman may (some day) want to note that there is a difference between a vectors capacity and its size. Setting the size (like resize(3) or via the vector(3) construct) will initialize each member with a default value. I would recommend not to set size directly but instead use push_back to grow the vector as data is needed to ensure the data in the vector makes sense and then, as an allocation optimization that doesn't change the validity of the program, perhaps call reserve first if the number is known in advance.
 
Last edited:
  • Like
Likes yungman
jtbell said:
Your original code for the operator,
C++:
int& operator[] (int position) { return Ivar[position].amount; }
works fine for me, after fixing your other error.

Your real problem is in trying to declare vector<Directory> Ivar(3); as a member of class VecA.

(Aside: When you have several compiler errors, it's always a good idea to tackle the first one first. Errors early in the code can trigger apparent errors in later code that's actually OK.)

I totally understand why you tried to do it this way. When you declare an array of three Directory's and a vector of three Directory's in the body of a function, you do this:
C++:
Directory ArrA[3];
vector<Directory> VecA(3);
It's natural to assume that because you declare an array same way in a class definition, you can do likewise with the vector. Unfortunately, that doesn't work, because the "declaration" of the vector above isn't a pure declaration. The "(3)" invokes a specific non-default constructor of class vector. In the context of a class definition, you have to do that in a constructor for that class.

Filip showed you one way. I'll show you a couple of other ways that might be easier to follow, but might have disadvantages in efficiency or whatever, compared to his method.

Both methods (and Filip's) declare the vector as simply vector<Directory> Ivar; i.e. as an "empty" vector with zero length to start with. Now let's focus on your constructor for VecA, which has to fix the size of the vector.

Method 1: resize the vector in the body of the VecA constructor:

Add the statement Ivar.resize(3); at the beginning of the constructor. I think you can do this yourself. This method uses the default vector constructor to create an empty vector, when the VecA constructor starts up; then resizes the vector to the desired size.

Method 2: Use the VecA constructor's initializer list:

C++:
    VecA(int sub1, int sub2, int sub3) : Ivar(3)
      { Ivar[0].amount = sub1; Ivar[1].amount = sub2; Ivar[2].amount = sub3; }
The initializer at the end of the first line invokes the appropriate vector constuctor on Ivar directly, before any of the code in the body of the VecA constructor is executed. This is a bit more efficient than the first method, because it sets up the vector in one step (construction) instead of two (construction and resizing).
That's exactly what happened. I woke up thinking about that, I put the vector declaration out on top of the class declaration and it worked...even before I read your post.

Now I have to spend time going through your post and Filip's post and learn that. I just getting into [] overload, I am still not quite getting use to the idea those overload operators are completely separate from the class and keep putting the class name in front of it regardless what to return.

Thanks
 
  • #10
yungman said:
I am still not quite getting use to the idea those overload operators are completely separate from the class and keep putting the class name in front of it regardless what to return.
No, the overloaded operators are NOT separate from the class they are part of. All of the members of a class are part of the class, which includes data members, function members, and any overloaded operators you throw in.

You should only put the class name at the beginning if the operator is intended to return an object of the class. If the operator is intended to return, say, an int, then the header for the operator would look like this: int operator XX().
An operator could return an object or a reference to an object, as in these examples:
C++:
Vec operator XX()
Vec& operator YY()
 
  • Like
Likes yungman
  • #11
Filip Larsen said:
What doesn't work?

Perhaps you can find inspiration in the following working example:
C++:
//C++ 17
#include <iostream>
#include <vector>

using namespace std;

class DirectoryVector {
    struct Directory {
        string name;
        int amount;
    };
    vector<Directory> entries;
   
public:
    DirectoryVector(const vector<int>& initialAmounts) {
        entries.reserve(initialAmounts.size());
        for (auto &amount : initialAmounts) {
            entries.push_back({"", amount});
        }
    }

    int operator[](int index) const {
        return entries.at(index).amount;
    }
};

int main()
{
    DirectoryVector dv({ 1, 2, 3});
    cout << "dv[2] = " << dv[2];

    return 0;
}
Thanks for you example, problem with me is I have not learn .reserve(0, .at() type of function. I have no idea what they are. I need to go with the more basic way.

thanks
 
  • Sad
Likes pbuk
  • #12
yungman said:
Thanks for you example, problem with me is I have not learn .reserve(0, .at() type of function. I have no idea what they are. I need to go with the more basic way.
These methods of std::vector are fundamental, there is no point using the class if you don't know how to use it. Yet again you have rejected the effort of someone who has invested their time and effort to give you an excellent template to follow and learn from. You will not progress this way.
 
  • Like
Likes Vanadium 50
  • #13
pbuk said:
These methods of std::vector are fundamental, there is no point using the class if you don't know how to use it. Yet again you have rejected the effort of someone who has invested their time and effort to give you an excellent template to follow and learn from. You will not progress this way.
It's easy for you to say, I am stretching already to go beyond the book and the video, there comes a point I have to draw the line and get on with the book. And thanks to other people that take the time to help me here.
 
Last edited by a moderator:
  • Sad
Likes jbriggs444
  • #14
jtbell said:
Your original code for the operator,
C++:
int& operator[] (int position) { return Ivar[position].amount; }
works fine for me, after fixing your other error.

Your real problem is in trying to declare vector<Directory> Ivar(3); as a member of class VecA.

(Aside: When you have several compiler errors, it's always a good idea to tackle the first one first. Errors early in the code can trigger apparent errors in later code that's actually OK.)

I totally understand why you tried to do it this way. When you declare an array of three Directory's and a vector of three Directory's in the body of a function, you do this:
C++:
Directory ArrA[3];
vector<Directory> VecA(3);
It's natural to assume that because you declare an array same way in a class definition, you can do likewise with the vector. Unfortunately, that doesn't work, because the "declaration" of the vector above isn't a pure declaration. The "(3)" invokes a specific non-default constructor of class vector. In the context of a class definition, you have to do that in a constructor for that class.

Filip showed you one way. I'll show you a couple of other ways that might be easier to follow, but might have disadvantages in efficiency or whatever, compared to his method.

Both methods (and Filip's) declare the vector as simply vector<Directory> Ivar; i.e. as an "empty" vector with zero length to start with. Now let's focus on your constructor for VecA, which has to fix the size of the vector.

Method 1: resize the vector in the body of the VecA constructor:

Add the statement Ivar.resize(3); at the beginning of the constructor. I think you can do this yourself. This method uses the default vector constructor to create an empty vector, when the VecA constructor starts up; then resizes the vector to the desired size.

Method 2: Use the VecA constructor's initializer list:

C++:
    VecA(int sub1, int sub2, int sub3) : Ivar(3)
      { Ivar[0].amount = sub1; Ivar[1].amount = sub2; Ivar[2].amount = sub3; }
The initializer at the end of the first line invokes the appropriate vector constuctor on Ivar directly, before any of the code in the body of the VecA constructor is executed. This is a bit more efficient than the first method, because it sets up the vector in one step (construction) instead of two (construction and resizing).

Thanks so much Jtbell. Yes, when I put inside the constructor like in your first example, it works.

Is it because Vector is a class template, not as simple as array? I still have to learn template in the near future. I am pushing way out of the book already. If I follow straightly to the book, I feel I literally learn nothing.

thanks so much for your help.
 
  • #15
I am looking into make the program more interesting, I want to input name and amount and push_back into the vector in the class VecA. Then I want to be able to read it back. Of cause there are issues. I have only one operator[](), if I want to do something like this below, I need to be able to both read and write to the vector. I might be able to use another operator=() to do one job. I just want to get some advice( say hint) which way to go.

This is what I am trying to do, it's not a completer program, just show I want to keep entering name and amount and call to push back into the vector Ivar. Then after I am done, read back the whole list.

C++:
class VecA
{
private: struct Dir { char name[25]; int amount; };//declare a structure
         vector<Dir>Ivar; //declare vector of structure Dir
public:    VecA(char*desc, int amt)  {}
        int &operator[](const int position){  return Ivar[position].amount;}
        void operator=(Dir& rhs) {}//Only one operator=()
};

int main()
{
    char more;
    VecA V;
    struct info { char name[25]; int amount; };
    info person;//declare structure person.
//Input information to person and  push_back into vector Ivar.   
    do
    {
        cin.ignore();
        char name[25];
        int number, amount;
        cin.getline(person.name, 25);
        cin >> person.amount;
        V = person;//using operator=() to copy person into vector to push_back.
        cin.get(more);
    } while (tolower(more) == 'y');
//read back from vector Ivar
    while (!= = false)
        {person = V;//read from Ivar starting from 0.
        //display information
        }
    return 0;
}
I know if I use conventional way, it would be too easy like setName(), getName() etc. I am trying to use overloading operators. Any advice would be helpful.
Thanks
 
Last edited:
  • #16
yungman said:
problem with me is I have not learn .reserve(0, .at() type of function. I have no idea what they are.
Any time you use an STL template class, like vector, or array, or whatever, you should investigate the methods (class functions) and operators that come with the class. A resource I use a lot is cplusplus.com. The VS docs are also helpful.
yungman said:
I might be able to use another operator=() to do one job.
Not the way you show it below. operator=() should not be type void. This operator needs to return something.
yungman said:
void operator=(Dir& rhs) {}//Only one operator=()
operator=() let's you assign one object to another of the same type. If a and b are objects of some type, you can use an overloaded operator=() like this:
C++:
a = b;
which is really like this:
C++:
a.operator=(b);
yungman said:
it would be too easy like setName(), getName() etc. I am trying to use overloading operators. Any advice would be helpful.
That's the way that things are usually done; i.e., with setters and getters. I can't think of a good reason to overload an operator to do either of these tasks.
 
  • Like
Likes pbuk, yungman and Vanadium 50
  • #17
Thanks Mark, I am just thinking out loud, the other voice to me is just let it go and go back to the book! Just finish the chapter and move on. I have times that I spent a lot of time on something, then I found out there is a better way in the later chapters. I think I need to take a night off, I already have a taste using vector here, that's more than the book offers already!
 
  • #18
I am so glad Chapter 14 is coming to an end! Getting ready for the last chapter Inheritance and Polymorphism. Finally the book comes to an end...Last chapter!

My question is how useful in real life are these overload operators? I read from someone that it's more fancy stuffs than really useful in real life programming. Can someone give me a real working example program maybe I can play around like I did with Jtbell's program? If it is useful, I don't think I really learn that deep other than the part in Jtbell's program.

thanks
 
  • #19
yungman said:
how useful in real life are these overload operators?
As a physicist, I would much rather be able to program an equation such as $$\vec r = {\vec r}_0 + {\vec v}_0 t + 0.5 {\vec a} t^2$$ as
C++:
r = r0 + v0 * t + 0.5 * a * t^2
than as something like
C++:
r = vsum (vsum (r0, vsum (vmul (v0, t), 0.5 * a * pow (t, 2))))
 
  • #20
jtbell said:
As a physicist, I would much rather be able to program an equation such as $$\vec r = {\vec r}_0 + {\vec v}_0 t + 0.5 {\vec a} t^2$$ as
C++:
r = r0 + v0 * t + 0.5 * a * t^2
than as something like
C++:
r = vsum (vsum (r0, vsum (vmul (v0, t), 0.5 * a * pow (t, 2))))
But you still need a lot of work to overload this in the program just to make it look better. Not to mention it is definitely extra steps to do the over loading and more chance to make mistakes.

BTW, that's only calculation of magnitude, still need to know the vector part of it. 😊 can you overload that much? Must be very difficult to do this using overloading.

thanks
 
Last edited:
  • #21
yungman said:
My question is how useful in real life are these overload operators?

Some types of operator overloads are very common. I guess you already familiar with general assignment operator, operator= and the std::vector::operator[], but in the standard library you will also find a lot of use of operator(), often used for functors, and operator<< and operator>> for input/output via the iostream library. Another example could be std::string which defines operator+ and operator[] in addition to several others.

As jtbell writes, its also quite common for math libraries (e.g. eigen) to overload the arithmetic operators when it makes sense, that is, when the math and code can be made to look similar without adding confusion.

yungman said:
I read from someone that it's more fancy stuffs than really useful in real life programming.

A good rule of thumb is not to use operator overloading unless it actually is helpful and has a clear meaning. Remember, even modern C++ allows you to shoot yourself repeatedly in the foot if you insist, and overuse of operator overloading is a common C++ code smell.
 
  • Like
Likes yungman
  • #22
yungman said:
BTW, that's only calculation of magnitude, still need to know the vector part of it. 😊 can you overload that much? Must be very difficult to do this using overloading.

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;
}
 
  • Like
Likes yungman
  • #23
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 am looking a little into your program. Do you mean you can do overloading on struct also? It works just the same?

Thanks
 
  • #24
yungman said:
Do you mean you can do overloading on struct also? It works just the same?

If you are referring to the class definition starting with struct instead of class, then yes, don't let that confuse you. A struct is, in short, just a class where the default access (until you declare it to something else) is public, including any inheritance used. For class declarations the default access is private, so you have to use the public keyword to change.

For instance, in the example below the apple and orange class are effectively defined with the same access, i.e. public:

C++:
struct apple : fruit {
    void eat();
};

class orange : public fruit {
public:
    void eat();
}

Regarding if it is a good idea to use struct or class, it is just a (half-automatic) habit of mine to use struct for small examples where everything is public to indicate a simple value class where nothing is hidden. For more involved classes with hidden state it is by far recommended and common practice to define it using class.
 
  • Like
Likes yungman
  • #25
Are you determine to stop me from studying chapter 15?? 😊 😊 :biggrin:

I have question in comments. I want to verify line 8 is constructor with default value of all 0, but then just x=x, y=y, z=z from input.
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) {}
//Constructor  vec3(x=0,y=0,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()
{// 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?
    double t = 2.0;
    vec3 r = r0 + t*v0 + 0.5 * a * t * t;//declare r is object of vec3 where vec3 r = ...
    cout << "r = " << r << endl;

    return 0;
}

Thanks
EDIT:

I am missing something, vec3 consists of x, y, z all separate numbers. How can vec3 r = r0 + t*v0 + 0.5 * a * t * t ? This implies object r is a single number after solving r0, v0 and a.
 
Last edited:
  • #26
yungman said:
I have question in comments.

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.
 
  • #27
yungman said:
I am missing something, vec3 consists of x, y, z all separate numbers. How can vec3 r = r0 + t*v0 + 0.5 * a * t * t ? This implies object r is a single number after solving r0, v0 and a.
Look at this code:
C++:
vec3 r = r0 + t*v0 + 0.5 * a * t * t
The only way you can think that r is a 'single number' is if you do not understand the significance of vec3 at the beginning of the line. What do you think that does here?
 
  • Like
Likes Vanadium 50
  • #28
jtbell said:
As a physicist, I would much rather be able to program an equation such as $$\vec r = {\vec r}_0 + {\vec v}_0 t + 0.5 {\vec a} t^2$$ as
C++:
r = r0 + v0 * t + 0.5 * a * t^2
than as something like
C++:
r = vsum (vsum (r0, vsum (vmul (v0, t), 0.5 * a * pow (t, 2))))

I would make one change - I would much rather be able to maintain code...

You write code once. But you will need to modify it (or debug it) many times. It's better to optimize code for ease of reading than ease of writing. Your example does both. Clarity of intent is the key.

PS What's that XOR doing in t^2?
 
  • #29
Vanadium 50 said:
PS What's that XOR doing in t^2?
Good question! I must have been thinking of some other language that uses '^' for exponentiation. :oops:
 
  • #30
jtbell said:
C++:
r = vsum (vsum (r0, vsum (vmul (v0, t), 0.5 * a * pow (t, 2))))
Oops, a is a vector (see the original equation), so that should actually be something like
C++:
r = vsum (vsum (r0, vsum (vmul (v0, t), vmul (a, 0.5 * pow (t, 2)))))
This assumes of course that vsum() and vmul() return vectors, which is easily done in C++.

Back when I was a grad student about 40 years ago, I was doing this sort of thing in Fortran, which doesn't (or at least didn't) allow returning arrays from functions like that. I had a library of subroutines (void functions in C/C++) like vsum(a, b, sum) that returned a vector result as an argument. I couldn't combine all the calculations above into a single statement. I could have done something like
Fortran:
vmul (v0, t, term2)
vmul (a, 0.5*t**2, term3)
vsum (r0, term2, r)
vsum (r, term3, r)
...but it was easier to do it component by component in a do-loop:
Fortran:
do k = 1, 3
    r(k) = r0(k) + v0(k) * t + 0.5 * a(k) * t**2
end do
 
  • #31
jtbell said:
Good question! I must have been thinking of some other language that uses '^' for exponentiation.

Why not overload ^ to mean exponentiation?
Hint: It doesn't work.
Hint: It's subtle.
Hint: It's so subtle it's likely to work in tests but not in real code.
 
  • #32
yungman said:
But you still need a lot of work to overload this in the program just to make it look better. Not to mention it is definitely extra steps to do the over loading and more chance to make mistakes.
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.
yungman said:
BTW, that's only calculation of magnitude, still need to know the vector part of it. 😊 can you overload that much? Must be very difficult to do this using overloading.
Not at all. And you have seen numerous examples in this thread.
yungman said:
I am missing something, vec3 consists of x, y, z all separate numbers. How can vec3 r = r0 + t*v0 + 0.5 * a * t * t ? This implies object r is a single number after solving r0, v0 and a.
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.)
 
Last edited:
  • Like
Likes Vanadium 50
  • #33
It might be worth pointing out that "cout << data" uses an overloaded operator.
 
  • #34
yungman said:
How can vec3 r = r0 + t*v0 + 0.5 * a * t * t ?
It would be useful for you to go back and review variable declarations. In my version of Gaddis, this is at the very beginning of the book - Ch. 1 page 12.
 
  • Love
  • Like
Likes pbuk and Vanadium 50
  • #35
Vanadium 50 said:
Hint: It's so subtle it's likely to work in tests but not in real code.

Hint: There are certain rules for operators that remains fixed even when overloaded, which can trick people into shooting themselves in the foot, especially for expressions containing a mix of operators. Overloading operator^ to mean exponentiation is a prime example.
 
  • #36
Filip Larsen said:
Hint:

I see you tried this once too. :smile:
 
  • #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.
 
Back
Top