Question on this overload program

  • Thread starter yungman
  • Start date
  • Tags
    Program
In summary: This variable goes out of scope after the constructor finishes, so the address becomes invalid. That's why when you try to print out the name in operator+(), you get garbage.To fix this, you should allocate memory for the "name" variable using the "new" keyword, similar to what you are doing in the other constructors. This will ensure that the variable's address remains valid even after the constructor finishes.In summary, the issue with the garbage output is due to assigning the address of a local variable to a member variable. To fix this, you should allocate memory for the variable using the "new" keyword. This will ensure
  • #71
Mark44 said:
. It seems very likely to me that the std namespace has a definition for something called size, and the compiler can't tell which one you mean: the size in the std namespace or the size that you have defined.

You are correct.
 
Technology news on Phys.org
  • #72
Mark44 said:
Sure it is -- it compiles without error and it runs and produces correct results.

Here's from my class definition:
C++:
#include <iostream>
#include <cstring>

using std::cout; using std::endl;
using std::ostream;
const int SIZE = 25;

class ThreeVector
{
private:
    double x, y, z;
    char name[SIZE];
    int serialNum;          // unique for each ThreeVector instance
    static int numVectors;  // counts the number of ThreeVectors constructed
... <public members>

A possible reason for the problem you're seeing is that you have using namespace std;
I said a long time ago that bringing the whole namespace in like this is a bad idea. It seems very likely to me that the std namespace has a definition for something called size, and the compiler can't tell which one you mean: the size in the std namespace or the size that you have defined.
Oh my god, you are correct. I never thought about that. Now I can at least move on. Never thought namespace std caused so much problem.

Thanks a million.
 
  • #73
yungman said:
really test out how much I really understand this.
Here's a test:

Q1. Explain using the terms 'declaration' (or declare) and 'initialisation' (or initialise) why this code does not make sense:
C++:
const int size;

Q2. `Give 2 reasons why this code doesn't work:
C++:
char name[25];
name[25] = "alan";

Mark44 said:
yungman said:
I am looking at your code, it doesn't seem to me that it's better than my very first post.
Sure it is -- it compiles without error and it runs and produces correct results.
Made my day :DD.
 
  • Like
Likes Mark44
  • #74
Mark44 said:
I said a long time ago that bringing the whole namespace in like this is a bad idea.

Yes you did. However, I think there are degrees of badness:

C++:
#include<iostream>
using namespace std;
int main() {
   cout << "Test.\n";
   return(0);
}

is very bad, because it infects everything.

C++:
#include<iostream>
int main() {
   using namespace std;
   cout << "Test.\n";
   return(0);
}

is better, because it only infects main(). In a subroutine, this is better. In a member function, better still.

C++:
#include<iostream>
int main() {
   using std::cout;
   cout << "Test.\n";
   return(0);
}

is even better still, because it brings in only the one needed element, so the odds of a collision go way down.
 
  • #75
pbuk said:
Here's a test:

Q1. Explain using the terms 'declaration' (or declare) and 'initialisation' (or initialise) why this code does not make sense:
C++:
const int size;

Q2. `Give 2 reasons why this code doesn't work:
C++:
char name[25];
name[25] = "alan";
Made my day :DD.
First question, it was a mistake, somehow I deleted it when I copied over.
Second is easy, I just learn it today. Need to use strncpy_s(name, 25, "alan", 25).
 
  • #76
pbuk said:
Q2. `Give 2 reasons why this code doesn't work:
C++:
char name[25];
name[25] = "alan";
yungman said:
Second is easy, I just learn it today. Need to use strncpy_s(name, 25, "alan", 25).
No, you didn't answer what @pbuk asked you to do, which was to give 2 reasons why that code doesn't work. He didn't ask you to do it another way.
 
  • Like
Likes Vanadium 50
  • #77
Mark44 said:
No, you didn't answer what @pbuk asked you to do, which was to give 2 reasons why that code doesn't work. He didn't ask you to do it another way.
Yes I did! First one I forgot the 25. the second one is using the wrong =, can't do that with c-strings. Isn't that obvious?
 
  • #78
You can define your const int size = 25 inside the class, as member data, but you have to make it static, presumably because that value is intended to be shared among all the instances of the class.
C++:
class Vec
{private:
    int x, y, z;
    static const int size = 25;
    char name[size];
// etc.
};
Hmmm... when I try to make it non-static (const int size = 25;), g++ gives me merely a warning message, not an error: in-class initialization of non-static data member is a C++11 extension.

Which version of C++ does VS default to? It might depend on which version of VS you're using.
 
  • Like
Likes yungman
  • #79
jtbell said:
You can define your const int size = 25 inside the class, as member data, but you have to make it static, presumably because that value is intended to be shared among all the instances of the class.
C++:
class Vec
{private:
    int x, y, z;
    static const int size = 25;
    char name[size];
// etc.
};
Hmmm... when I try to make it non-static (const int size = 25;), g++ gives me merely a warning message, not an error: in-class initialization of non-static data member is a C++11 extension.

Which version of C++ does VS default to? It might depend on which version of VS you're using.
I am glad you are here. This is an extension YOUR thread! I just don't want to hijack your thread so I started my own. My VS is 2019.

To me, your thread was quite clear on what steps the compiler was doing. I carried on one step more, I want to look when I give a c-string to the class, I want to see how it is being copied. I am not convinced at all that there is a solution to copy the c-string over yet. In the very first post, I showed the name is not passed from what you called Vector#4(sum) to Vector#5(some temporary). There is a miss connection there and I got garbage when I print out the c-string of Result( which is your c).

About the "size", this has been resolved thanks to Mark. I just don't use using namespace std. Or maybe changing the name size.

Thanks
 
Last edited:
  • #80
Apparently I still running into issue of passing c-string as parameter. Here is the very short program and you can see one way works and the other doesn't:
C++:
#include <iostream>
#include <cstring>
using std::ostream;
using std::cout; using std::endl;
const int size = 25;
class Vec
{private:
    int x, y;
    char name[size];
public:
    Vec(int x0, int y0, char *desc)
        { x = x0, y = y0;
          strncpy_s(name, size, desc, size);        
        }
};
int main()
{    char vecA[size] = "vecA";
    Vec a(1, 2, vecA);//This works
    Vec b(2, 4, "vecB");//This doesn't work.
    return 0;
}
Error.jpg

Line 20 just won't work. Why?

Thanks
 
  • #81
yungman said:
Line 20 just won't work. Why?
Already answered. See post #67. Again, please read what others and I write. It's disrespectful to us and wasteful of our time when we answer a question that you've asked, and you don't read the responses, and ask the same question again.

No, you still didn't answer what @pbuk asked you to do, which was to give 2 reasons why the code below doesn't work.
C++:
char name[25];
name[25] = "alan";

yungman said:
the second one is using the wrong =, can't do that with c-strings. Isn't that obvious?
If that's the wrong =, is there another = that works? What's your second reason?
 
  • #82
yungman said:
Line 20 just won't work. Why?
Mark44 said:
See post #67.
To elaborate a bit on the statement in post #67:

A literal string such as "vecB" doesn't have type char *. It implicitly has type const char *, because it makes no sense to change the value of a literal string.

You can't pass a const char * to a function that declares a parameter to be char *. When you declare a parameter without specifying const, it signals to the compiler that the function might change the value of the parameter.

Therefore, if you want to be able to pass a literal string to a function, you must declare the parameter as const char *.

(On the other hand, you can pass a char * (e.g. a char array that isn't declared as const) to a function that declares a parameter as const char *.)

[oops, yungman quoted this while I was editing it for clarity.]
 
Last edited:
  • Like
Likes yungman
  • #83
jtbell said:
To elaborate a bit on the statement in post #67:

A literal string such as "vecB" doesn't have type char *. It has type const char *.

You can't pass a const char * to a function that declares a parameter to be char *. When you declare a parameter without specifying const, it signals to the compiler that the function might change the value of the parameter. However, it makes no sense to change the value of a literal string, so those are always implicitly const char *.

(On the other hand, you can pass a char * (e.g. a char array that isn't declared as const) to a function that declares a parameter as const char *.)
THANK YOU
This is what I need. I have not seen any explanation on this before. That's why I make mistake and don't even know why. Whole day today has been tripped by the c-string copying and passing parameter. this definitely will be in my notes.

that's why when I read Marks reply again, I still didn't understand until your post just pop up! Just like in your thread, everyone replied sounded like they think everyone knew all that, that was NEW to me, that was an eye opener! That's why I spent over a week now on your post and I refuse to move on until I get everything to learn out of it.

Actually I am in the process of writing out the program without looking at any of the stuff, line by line reasoning out, step by step doing it again.

Thanks
 
  • #84
You might want to check the revised version of my post. I was in the middle of editing it when you quoted it. I didn't change the main point, just tried to make it clearer (hopefully).
 
  • #85
jtbell said:
You might want to check the revised version of my post. I was in the middle of editing it when you quoted it. I didn't change the main point, just tried to make it clearer (hopefully).
Can you tell me which post #?

thanks
 
  • #86
yungman said:
Actually I am in the process of writing out the program without looking at any of the stuff
Please stop!
Read through this thread before you start writing out the program. At the very least, doing so might eliminate more questions that we've already answered.
 
  • Like
Likes Vanadium 50
  • #87
I did it. My biggest road block is about the passing and copying c-string. After learning all those today thanks to Mark and Jtbell, it is very smooth to write my own. I wrote the whole program with very little peeking to the existing programs. It is actually different enough from Jtbell's. I think I understand Jtbell's thread, I am ADDING to the program and remove some of the stuffs like the Vector# and z. I am concentrating on passing the c-string around and make sure it's not shallow copying. I did it!

I actually think about what I was writing to write the code, why I put const in front of the variable types like const char*. I got it done quite fast. this is my program:
C++:
#include <iostream>
#include <cstring>
using std::ostream;
using std::cout; using std::endl;
const int size = 25;
class Vec
{private:
    int x, y;
    char name[size];
public:
    Vec(){ x = 0, y = 0;
        strncpy_s(name, size, "Default", size);
        cout << " [In Dconstructor], object created: " << name <<
            "(" << x << "," << y << ")   address: " << this << "\n\n";
    }
    Vec(const char*desc) { x = 0, y = 0;
         strncpy_s(name, size, desc, size);
         cout << " [In Constructor], object created: " << name <<
         "(" << x << "," << y << ")   address: " << this << "\n\n";
        }
    Vec(int x0, int y0, const char *desc){ x = x0, y = y0;
         strncpy_s(name, size, desc, size);
         cout << " [In Constructor], object created: " << name <<
             "(" << x << "," << y << ")   address: " << this << "\n\n";
        }
    Vec(const Vec& original)
      {    x = original.x; y = original.y;
        strncpy_s(name, size, "Temp", size);
        cout << " [In Copy Constructor], object created: " << name <<
            "(" << x << "," << y << ")   address: " << this << "\n\n";
      }
    ~Vec(){cout<<" Destroying "<<(*this).name<<",   Address: "<<this<<"\n\n";}
    Vec operator+(const Vec& right)
      {  Vec sum;
         sum.x = x + right.x; sum.y = y + right.y;
         strncpy_s(sum.name, size, "sum", size);
         cout <<" [In OP+]: " << sum.name << "(" << sum.x << "," << sum.y <<
             ") = " << (*this).name <<"(" << (*this).x << "," << (*this).y <<
             ") + " << right.name <<"(" << right.x << "," << right.y << ")\n\n";
         return sum;
      }
    Vec& operator=(const Vec& rhs)
      {x = rhs.x; y = rhs.y;
       strncpy_s(name, size, rhs.name, size);
       cout << " [In OP=]: " << rhs.name << "(" << rhs.x << "," << rhs.y <<
           ")   is copied into   " << name << "(" << x << "," << y << ")\n\n ";
       return *this;
      }
    friend ostream& operator<<(ostream& out, const Vec& v)
      {out << " [OP<<] c contains: " << v.name << "(" << v.x << "," << v.y << ")\n\n"; return out; }
};

int main()
{    Vec a(1, 2, "vecA");
    Vec b(3, 4, "vecB");
    Vec c("vecC");
    c = a + b;
    cout << c << "\n\n";
    return 0;
}
Attached is the print out. I checked the address where the compiler go step by step.
I intentionally let "Temp" to copy over to object c so when I display c, I get Temp(4,6). This is by intention to show I successfully pass the literal c-string in every step.

Thanks everyone for the help. I am going to look at Mark's program and make it work tomorrow. I learn so much out of this exercise, it's a week of hard work worth while. I don't think I can do nearing half if I stick to the book. Now I feel good about the overloading operator a lot better than last week.

Thanks a million to everyone that helped me.
 

Attachments

  • Alan version of Jtbell program.docx
    11.8 KB · Views: 155
  • #88
Mark44 said:
@yungman, regarding the problem you were trying to solve when you opened this thread (adding a C-string name field to the class), here are some pieces of my solution. The code is based on what @jtbell posted.
The class definition, in what I'm calling ThreeV.h:
C++:
#include <iostream>
#include <cstring>

using std::cout; using std::endl;
using std::ostream;
const int SIZE = 25;

class ThreeVector
{
private:
    double x, y, z;
    char name[SIZE];
    int serialNum;          // unique for each ThreeVector instance
    static int numVectors;  // counts the number of ThreeVectors constructed
public:
    ThreeVector();                        // default constructor
    ThreeVector(double, double, double, const char*);
    ThreeVector(const char* name);
    ThreeVector(const ThreeVector&);      // copy constructor
    ~ThreeVector();
    ThreeVector operator+ (const ThreeVector&) const;
    ThreeVector& operator= (const ThreeVector&);
    friend ostream& operator<< (ostream& out, const ThreeVector& v);
};
A couple of the function definitions, in the same file:
C++:
// Default ctor
ThreeVector::ThreeVector()
{
    x = 0;  y = 0;  z = 0;
    strncpy_s(name, SIZE - 1, "Default", SIZE - 1);
    numVectors++;
    serialNum = numVectors;  
    cout << "-- Default-constructed vector #" << serialNum << endl; 
}
// Another ctor
ThreeVector::ThreeVector(double x0, double y0, double z0, const char * str)
{
    x = x0;  y = y0;  z = z0;
    strncpy_s(name, SIZE-1, str, SIZE - 1);
    numVectors++;
    serialNum = numVectors;
    cout << "-- Constructed vector #" << serialNum << endl;   
}

// Overloaded operator+()
ThreeVector ThreeVector::operator+ (const ThreeVector& rhs) const
{
    ThreeVector sum("Sum");
    sum.x = x + rhs.x;  sum.y = y + rhs.y;  sum.z = z + rhs.z;
    cout << "Return from operator+..." << endl;
    return sum;  
}
Not shown are
  • a constructor that initializes the name portion with a specified string, and initializes the other data members to 0
  • a copy constructor
  • the destructor (same as jtbell posted)
  • overloaded operator=()
  • overloaded operator<<() (same as jtbell posted)
The class consumer:
C++:
#include <iostream>
#include "ThreeV.h"
using std::cout; using std::endl;

int main()
{  
    cout << "Declare a and b..." << endl;
    ThreeVector a(1, 2, 3, "VecA"), b(4, 5, 6, "VecB");
    cout << "a: " << a << " b: " << b << endl;
    cout << "Declare c and add c = a + b..." << endl;
    ThreeVector c;
    ThreeVector d("VecD");
    cout << "c: " << c << " d: " << d << endl;
    c = a + b;
    cout << "c: " << c << endl;
    cout << "Return from main()..." << endl;  
}
Hi Mark

I look through your program one more time. I hope I don't offend you, I think you missed my point from my first post. I have no problem printing out name of a, b and c( in your program is vecA, vecB and vecC) right from the beginning. If you look at my first post and the print out, you would see I got those already. My issue is the name in Temp got lost when copy from sum to Temp and thereby getting garbage in the final Result(which is vecC in your program).

You only provided the part that I already did in my very first post by constructors with names. ( I use name = new char[]). My question are ALL in Copy Constructor and operator=() which you have not addressed. That's what I was working on through out the whole thread here. that's why when you ask me to work with your program, I already kind of know that's not it already.

But I thank you for getting me through the issue of copying c-string and passing c-string as parameter using const char*desc. It turn out that's all the problem with me. After I understand from you and Jtbell, I have no issue writing the program one time through tonight. Now I proof I can write program with these few operators and constructors.

If you look at my final program, I actually copy the name from sum and change to Temp, then actually overwrite vecC to Temp in c step by step. When I print out c, I actually get Temp to proof I actually passing the c-string name over. It doesn't make sense, BUT that's what I set out to do in the very first post. This conclude my questions in this thread.

Thanks you so much for your help and patience. This thread is so important for me to understand deeper into overloading and more importantly, learn to look at how the compiler think.

Thanks
 
  • #89
yungman said:
Can you tell me which post #?

thanks
The one you were replying to... #82.
 
  • Like
Likes yungman
  • #90
jtbell said:
The one you were replying to... #82.
Oh good!, I need to edit my notes, I literally copy part of your post 82 into my notes. I thought you were talking about in your thread.

Thanks
 
Back
Top