Making my own toString() method on c++ struct - c++

I'm used to oveerriding the Java toString() method on my own objects in classes, but I'm not sure where I'm going wrong with the following code:
struct Student {
std::string name;
int age;
double finalGrade;
std::string toString() {
return "Name: " + name + "\n Age: " + age + "\n Final Grade: " + finalGrade;
}
};
I'm only beginning to learn c++ so any advice would be appreciated

In contrast to java, C++ does not offer a predefined "toString"-method that is called implicitly whenever a string representation of an object is requested. So your toString-method will have to be called explicitly then.
In C++, however, something similar is available by overriding the operator << for streams. Thereby, you can directly "send" the object contents to a stream (without the need to store everything in an intermediate string object). And you can use the same code to populate a string to be returned by a toStringmethod, too:
struct Student {
std::string name;
int age;
double finalGrade;
std::string toString() const;
};
ostream& operator << (ostream &os, const Student &s) {
return (os << "Name: " << s.name << "\n Age: " << s.age << "\n Final Grade: " << s.finalGrade << std::endl);
}
std::string Student::toString() const {
stringstream ss;
ss << (*this);
return ss.str();
}
int main() {
Student stud { "john baker", 25, 1.2 };
std::cout << "stud directly: " << stud << endl;
std::string studStr = stud.toString();
std::cout << "stud toString:" << studStr << endl;
}

You can't add anything you want to a std::string like you can to a Java String. Notably, most objects are not expected to have a toString member function. However, the standard library provides std::to_string which allow you to convert numeric values to an std::string. For example you could wrap the numeric values with a std::to_string to fix your function :
#include <string>
struct Student {
std::string name;
int age;
double finalGrade;
std::string toString() {
return "Name: " +
name +
"\n Age: " +
std::to_string(age) +
"\n Final Grade: " +
std::to_string(finalGrade);
}
};
Edit : Though this answer explains why what you tried doesn't work, the other answer's solution is the preferred approach.

You cant add int to std::string because the std::string operator+ was not overloaded to int.
The best solution is to use string stream :
#include <sstream>
std::string toString() {
std::ostringstream strout;
strout<< "Name: " << name << "\n Age: " << age << "\n Final Grade: " << finalGrade;
return strout.str();
}

You cannot just add an int or a double to an std::string. Use std::to_string to convert them first. This should work fine:
std::string toString() {
return "Name: " + name + "\n Age: " + std::to_string(age) + "\n Final Grade: " + std::to_string(finalGrade);
}

Related

Having trouble with objects and classes in C++

So, I defined the method displayStudInfo in the 'Student' Class and called it in the main function. But I'm getting the error "Function not declared in this scope". Can anyone please tell me why this is happening and what I can do to solve this problem?
#include <iostream>
#include <string>
using namespace std;
class Student{
public:
int age;
string name;
void enterInfo(){
cout << "Enter your age = " ; cin >> age;
cout << "Enter your name = "; cin >> name;
}
void displayStudInfo(Student s)
{
cout << "Age = " << s.age << ", name=" << s.name << endl;
}
};
int main(){
int size;
Student stud[100];
Student abir;
abir.enterInfo();
displayStudInfo(abir);
}
In your case void displayStudInfo(Student s) is a member function of Student so you have to call it on an instance of Student, the same way you did with enterInfo.
You can solve that in different ways. One way is to make that member function a free function by moving it out of the body of the Student
class Student{
public:
// … 
};
void displayStudInfo(Student s)
{
cout << "Age = " << s.age << ", name=" << s.name << endl;
}
int main(){
// … 
displayStudInfo(abir);
}
displayStudInfo is, in fact, a good candidate for a free function. Or you make it static which is similar to a free function, and access the static member function using Student::displayStudInfo(abir).
The other way would be to call displayStudInfo on abir in that case you don't need the Student argument, as abir is implicitly passed to displayStudInfo.
class Student{
public:
// … 
void displayStudInfo()
{
cout << "Age = " << age << ", name=" << name << endl;
}
};
int main(){
// … 
abir.displayStudInfo();
}
void displayStudInfo(Student s) hidden in side class.
So, its not accessible in main().
Try:
void displayStudInfo()
{
cout << "Age = " << age << ", name=" << name << endl;
}
call in main():
abir.displayStudInfo();
In C++, all member functions implicitly receive a parameter which points to the current object. This parameter is the this pointer.
Therefore, it doesn't make sense for you to specify an additional (explicit) parameter for the object in your definition of the function displayStudInfo.
It would make sense to rewrite the function definition to
void displayStudInfo()
{
cout << "Age = " << age << ", name=" << name << endl;
}
and to call it with
abir.displayStudInfo();
instead of
displayStudInfo(abir);
Alternatively, you could make the function displayStudInfo a non-member function, by putting it outside the declaration of class Student. In that case, you would have to keep the explicit parameter, because that parameter is only passed implicitly to member functions.

C++ output all members in a object

So far I have defined a simple class...
class person {
public:
string firstname;
string lastname;
string age;
string pstcode;
};
...then added some members and values to an object named "bill"...
int main() {
person bill;
bill.firstname = "Bill";
bill.lastname = "Smith";
bill.age = "24";
bill.pstcode = "OX29 8DJ";
}
But how would you simply output all those values? Would you use a for loop to iterate over each member?
I typically override operator <<, so that my objects are as easy to print as any built-in object.
Here is one way to override operator <<:
std::ostream& operator<<(std::ostream& os, const person& p)
{
return os << "("
<< p.lastname << ", "
<< p.firstname << ": "
<< p.age << ", "
<< p.pstcode
<< ")";
}
And then to use it:
std::cout << "Meet my friend, " << bill << "\n";
Here is a complete program using this technique:
#include <iostream>
#include <string>
class person {
public:
std::string firstname;
std::string lastname;
std::string age;
std::string pstcode;
friend std::ostream& operator<<(std::ostream& os, const person& p)
{
return os << "("
<< p.lastname << ", "
<< p.firstname << ": "
<< p.age << ", "
<< p.pstcode
<< ")";
}
};
int main() {
person bill;
bill.firstname = "Bill";
bill.lastname = "Smith";
bill.age = "24";
bill.pstcode = "OX29 8DJ";
std::cout << "Meet my friend, " << bill << "\n";
}
Simplistically, you output each element using an ostream:
class Person
{
public:
void Print_As_CSV(std::ostream& output)
{
output << firstname << ",";
output << lastname << ",";
output << age << ",";
output << pstcode << "\n";
}
string firstname;
string lastname;
string age;
string pstcode;
};
There may be different methods of printing, which is why I didn't overload operator <<. For example, one data member per line would be another popular scenario.
Edit 1: Why not looping?
The class has separate fields, which is why you can't iterate over the members.
If you want to iterator or loop over the members, you either have to have an iterator for your class or use a container, such as std::vector, that provides iteration.

Copy from one structure to another structure of different type

I am trying this piece of code in vs 2008
#include <stdio.h>
#include <iostream>
#include <string>
typedef struct _first
{
int age;
std::string name;
}first;
typedef struct _second
{
int age;
char name[20];
}second;
void copy_structure()
{
first s;
second f;
f.age = 15;
cout<<"Enter the name"<<endl;
fgets(f.name, 20, stdin);
memcpy(&s,&f,20);
cout << "Name: " << s.name << endl;
cout << "Age: "<< s.age << endl;
}
int main()
{
copy_structure();
return 0;
}
while building I didn't get any error but when I run, name field is empty over here
cout << "Name: " << s.name << endl;
I am not getting any output over here, can somebody help me to solve this issue.
You should use an approach based on member-wise copying. For example
void copy_structure()
{
first f;
^^
second s;
^^
s.age = 15;
cout<<"Enter the name"<<endl;
fgets(s.name, 20, stdin);
f.age = s.age;
f.name = s.name;
cout << "Name: " << f.name << endl;
cout << "Age: "<< f.age << endl;
}
Otherwise the internals of the object name of the type std::string will be overwritten and the program will have undefined behaviour.
This looks like C but not like C++... Your current code will also brick your std::string instance. memcpy is dangerous and should not be used, unless you have a very, very good reason. I never had a reason for this so far.
My suggestion:
#include <iostream>
#include <string>
using namespace std;
struct second
{
int age;
char name[20];
};
struct first
{
int age;
string name;
first& operator=(const second& rhs);
};
// some operator for copying
first& first::operator=(const second& rhs)
{
age = rhs.age;
name = rhs.name;
return *this;
}
int main()
{
first s;
second f;
f.age = 15;
cout << "Enter your name" << endl;
cin >> f.name;
s = f;
cout << "Name: " << s.name << endl;
cout << "Age: " << s.age << endl;
return 0;
}
This is improvable, of course. You would usually rather use classes than structs. And you would might also have an operator>> for second.

Formatting stream spaces

I have been trying to use .pushback to format my string so that it prints just a space between every word.
So I was trying to use a .push_back, however that doesn't work with integers.
std::string FormatVehicleString(std::string year,
std::string make,
std::string model,
double price,
double mileage)
{
year.push_back(5);
make.push_back(5);
model.push_back(5);
price.push_back(5);
mileage.push_back(5);
}
Can someone point me in the right direction, is there another value type that will incorporate strings and integers?
One option is to use a std::ostringstream.
std::string FormatCarInfo(std::string year,
std::string make,
std::string model,
double price,
double mileage)
{
std::ostingstream out;
out << year << " ";
out << make << " ";
out << model << " ";
out << price << " ";
out << mileag ;
return out.str();
}
Another option is to use std::to_string.
std::string FormatCarInfo(std::string year,
std::string make,
std::string model,
double price,
double mileage)
{
return ( year + " " + make + " " + model + " " +
std::to_string(price) + " " + std::to_string(mileage) );
}

struct output with cout, and function call struct parameters

So, the problem is several errors at compile time.
ReadMovieData(string* title, string* director) cannot convert from movieInfo to string*
DisplayMovieData(string title, string director) cannot convert from movieInfo to string
No operator found which takes a right-hand operand of type 'movieInfo' (or there is no acceptable conversion.
The bottom error happens twice in DisplayMovieData() so I wrote it once for simplicity sake.
The ReadMovieData function should accept a structure pointer reference variable and the DisplayMovieData function should accept a MovieInfo structure variable.
The main function creates an array of 2 MovieInfo struct variables and the other functions should be called on an element of the array.
The code I have finished is below.
#include <stdafx.h>
#include <string>
#include <iomanip>
#include <iostream>
using namespace std;
//prototypes
int ReadMovieData(string* title, string* director);
int DisplayMovieData(string title, string director);
struct movieInfo {
string title, director;
};
int main(){
const int SIZE = 2;
movieInfo movieList[SIZE];
movieInfo movie;
//supposed to assign data to movieList[i] at some point
for (int i = 0; i < SIZE; i++){
ReadMovieData(movie, movie);
DisplayMovieData(movie, movie);
}
return 0;
}
int ReadMovieData(movieInfo &title, movieInfo &director){
movieInfo movie;
//get the movie name
cout << "What is the movie? ";
cin.ignore();
cin >> movie.title;
//get the movie director
cout << "What is the director of " << movie.title << "?";
cin.ignore();
cin >> movie.director;
return 0;
}
int DisplayMovieData(movieInfo title, movieInfo director){
cout << "The movie name is: " << title << endl;
cout << "The director of " << title << " is: " << director << endl;
return 0;
}
There are mismatches between your function prototypes and their definitions, as you can see comparing the parameter types in both.
Note that since you defined a structure for the movie info, you can directly pass it to the reading and displaying functions (instead of passing the single structure data member strings).
You may want to read the following compilable code:
#include <iostream>
#include <string>
using namespace std;
struct MovieInfo {
string title;
string director;
};
void ReadMovieData(MovieInfo& movie);
void DisplayMovieData(const MovieInfo& movie);
int main() {
const int SIZE = 2;
MovieInfo movieList[SIZE];
for (int i = 0; i < SIZE; i++) {
ReadMovieData(movieList[i]);
DisplayMovieData(movieList[i]);
}
}
// Since movie is an output parameter in this case, pass by non-const reference.
void ReadMovieData(MovieInfo& movie) {
//get the movie name
cout << "What is the movie? ";
cin >> movie.title;
//get the movie director
cout << "What is the director of " << movie.title << "?";
cin >> movie.director;
}
// Since movie is an input parameter in this case, pass by reference to const.
void DisplayMovieData(const MovieInfo& movie) {
cout << "The movie name is: " << movie.title << endl;
cout << "The director of " << movie.title
<< " is: " << movie.director << endl;
}
The errors are pretty explanatory and clear - your function takes string* but you're passing movieInfo - unrelated types can't just magicaly convert one to another.
What you probably want is pass the data members of movieInfo:
ReadMovieData(&movie.title, &movie.director);
It would be better if arguments were not pointers - use references instead. Where you won't be changing the arguments, the references should be to const type.
Even better, why not just pass moveInfo
ReadMovieData(movieInfo& movie);
and let the function deal with the internals of the class? This better encapsulates data and doesn't lead to spaghetti code quite so fast.
Also, the declarations and definitions need to match (otherwise you'd be overloading) - you're using pointers in some places and references/values in others.
Finally, here's how an overload of operator<< might look like:
std::ostream& operator<<(std::ostream& os, const movieInfo& m)
{
return os << "Title: " << m.title << ", Director: " << m.director;
}
Your class movieInfo does not have an overloaded << operator, which is necessary is you want to work with iostream, however, you can pass the strings contained in movieInfo:
int DisplayMovieData(string &title, string &director) { }
Call like:
DisplayMovieData(movie.title, movie.director);
You are declaring the function with this signature
int ReadMovieData(string* title, string* director);
but you're defining it using
int ReadMovieData(movieInfo &title, movieInfo &director) {
// ...
}
These don't match!
The code is totally invalid. I suppose the valid code should look the following way
#include <stdafx.h>
#include <string>
#include <iomanip>
#include <iostream>
using namespace std;
struct movieInfo
{
string title, director;
};
//prototypes
movieInfo ReadMovieData();
void DisplayMovieData( const movieInfo & );
int main()
{
const int SIZE = 2;
movieInfo movieList[SIZE];
//supposed to assign data to movieList[i] at some point
for ( int i = 0; i < SIZE; i++ )
{
movieList[i] = ReadMovieData();
DisplayMovieData( movieList[i] );
}
return 0;
}
movieInfo ReadMovieData()
{
movieInfo movie;
//get the movie name
cout << "What is the movie? ";
cin.ignore();
cin >> movie.title;
//get the movie director
cout << "What is the director of " << movie.title << "?";
cin.ignore();
cin >> movie.director;
return movie;
}
void DisplayMovieData( const movieInfo &movie )
{
cout << "The movie name is: " << movie.title << endl;
cout << "The director of " << movie.title << " is: " << movie.director << endl;
}