I am doing a practice problem in HackerRank, and I am having trouble implementing the final task for this one issue I am having with classes.
It is a pretty simple program, it just uses a Student class with setter and getter functions to take in a student's information (age, firstname, lastname, and academic standard), and uses an stringstream to output that data.
However, at the very end is where I am having trouble. I am supposed to create a to_string() function which returns a string consisting of the above elements, separated by a comma (,). I think I am just mis-understanding how to use ostringstream.
#include <iostream>
#include <sstream>
#include <string>
class Student{
private:
int age;
std::string first_name;
std::string last_name;
int standard;
public:
void set_age(int age){
age = age;
}
int get_age(){
return age;
}
void set_standard(int standard){
standard = standard;
}
int get_standard(){
return standard;
}
void set_first_name(std::string first_name){
first_name = first_name;
}
std::string get_first_name(){
return first_name;
}
void set_last_name(std::string last_name){
last_name = last_name;
}
std::string get_last_name(){
return last_name;
}
std::string to_string(){
std::stringstream os;
os << age << "," << first_name << "," << last_name << "," << standard << std::endl;
return os.str();
}
};
int main() {
int age, standard;
std::string first_name, last_name;
std::cin >> age >> first_name >> last_name >> standard;
Student st;
st.set_age(age);
st.set_standard(standard);
st.set_first_name(first_name);
st.set_last_name(last_name);
std::cout << st.get_age() << "\n";
std::cout << st.get_last_name() << ", " << st.get_first_name() << "\n";
std::cout << st.get_standard() << "\n";
std::cout << "\n";
std::cout << st.to_string();
return 0;
}
Input Example:
15
john
carmack
10
Expected output:
15
carmack, john
10
15,john,carmack,10
My output:
2
,
0
2,,,0
All of your class setters suffer from the same problem - each input parameter has the same name as its corresponding class member. As such, each parameter is shadowing the class member, so you end up assigning the input value back to the parameter, rather than to the class member.
Thus, none of your class members are actually being assigned any input values at all, which is why you are getting garbage in your output.
Once you fix the shadowing issue, you will get your expected output:
void set_age(int /*age*/value){
age = /*age*/value;
}
...
void set_standard(int /*standard*/value){
standard = /*standard*/value;
}
...
void set_first_name(std::string /*first_name*/value){
first_name = /*first_name*/value;
}
...
void set_last_name(std::string /*last_name*/value){
last_name = /*last_name*/value;
}
...
On a side note: to_string() should use std::ostringstream instead of std::stringstream. And to_string(), and all of the getters, should be marked as const, since they aren't modifying the Student object.
Online Demo
Related
I am trying to read into a nested struct from a txt file. The output keeps repeating the same nested output. I attempted to nest two for loop but it didn't even read at all, my display was a blank screen. So I was able to get the file to read now but it repeats the same title and yearPub information for all entries.
#include<iostream>
#include<string>
#include<fstream>
#include<iomanip>
using namespace std;
struct Discography {
string title;
int yearPub;
};
struct Collection {
string name;
string genres;
int startYear;
int endYear;
Discography records;
};
void readFile(ifstream&, string, Collection [], int&);
const int DATA_FILE = 10;
int main() {
ifstream inputMusic;
Collection music[DATA_FILE];
Discography records;
const int DISPLAY_ALL = 1,
SEARCH_ARTIST_NAME = 2,
SEARCH_GENRE = 3,
SEARCH_TITLE = 4,
SEARCH_YEAR = 5,
QUIT_CHOICE = 6;
int choice;
int count = 0;
int numFile = count;
string nameArtist,results;
readFile(inputMusic, "My_Artists.txt", music, count);
void readFile(ifstream& inputMusic, string data, Collection music[], int &count)
{
inputMusic.open(data);
if (!inputMusic)
{
cout << "Error in opening file\n";
exit(1);
}
else
{
while (!inputMusic.eof())
{
inputMusic >> music[count].name
>> music[count].genres
>> music[count].startYear
>> music[count].endYear
>> music[count].records.title
>> music[count].records.yearPub;
count++;
}
inputMusic.close();
}
return;
};
InputFile:
MJ
Pop
1980
2020
BAD 1990
DRE
Rap
1970
2022
CRONIC 1995
EMINEM
Rap
1998
2022
ENCORE 2002
WHITNEY
R&B
1974
2008
SOMEBODY 1987
OUTPUT:
Name : MJ
Genre: Pop
Start Year: 1980
End Year: 2020
Title: BAD Year Published: 1990
----------------------------------------------------
Name : DRE
Genre: Rap
Start Year: 1970
End Year: 2022
Title: BAD Year Published: 1990
----------------------------------------------------
Name : EMINEM
Genre: Rap
Start Year: 1998
End Year: 2022
Title: BAD Year Published: 1990
----------------------------------------------------
Name : WHITNEY
Genre: R&B
Start Year: 1974
End Year: 2008
Title: BAD Year Published: 1990
----------------------------------------------------
I would suggest going in a little different direction to make sure you don't write a lot of unneeded code. Here's the exact same example withe a few improvements. First improvement is the way you store your data. Instead of storing it in an array with seperate size variables and more arguments and that why not use vector. Next thing is the way you input data into your program. Not very clear. Better way would be saving it in csv file. Here's the code:
#include<iostream>
#include<string>
#include<fstream>
#include<iomanip>
#include<vector>
using namespace std;
struct Discography {
string title;
int yearPub;
Discography(string name, int publish) : title(name), yearPub(publish) {}
Discography() {}
};
struct Collection {
string name;
string genres;
int startYear;
int endYear;
Discography records;
Collection(string artistName, string genre, int start, int end, string title, int yearPublished)
: name(artistName), genres(genre), startYear(start), endYear(end), records(title, yearPublished) {}
Collection() {}
};
void readFile(vector<Collection> &music)
{
ifstream file;
file.open("myArtists.txt");
if (file.is_open())
{
string line;
while (getline(file,line))
{
int pos;
pos = line.find(';');
string name = line.substr(0, pos);
line = line.substr(pos+1);
pos = line.find(';');
string genre = line.substr(0, pos);
line = line.substr(pos+1);
pos = line.find(';');
int start = stoi(line.substr(0, pos));
line = line.substr(pos+1);
pos = line.find(';');
int end = stoi(line.substr(0, pos));
line = line.substr(pos+1);
pos = line.find(';');
string title = line.substr(0, pos);
int publish = stoi(line.substr(pos+1));
music.emplace_back(Collection(name,genre,start,end,title,publish));
}
}
else
{
cout << "Error in opening file" << endl;
}
file.close();
return;
};
void print(vector<Collection> &music)
{
for(int i = 0; i < music.size(); i++)
{
cout << "Name: " << music[i].name << endl
<< "Genre: " << music[i].genres << endl
<< "Start Year: " << music[i].startYear << endl
<< "End Year: " << music[i].endYear << endl
<< "Title: " << music[i].records.title << " Year Publiszed: " << music[i].records.yearPub << endl
<< "----------------------------------------------------" << endl << endl;
}
}
int main() {
vector<Collection> music;
readFile(music);
print(music);
}
There are constructors for the structs enabling quick and easy one line creation of the objects. This coupled with vectors' dynamic size and implemented add function emplace back makes it really easy to add to the list. Now the only thing left is to gather the data from the file. To make it more clear its always best to use a csv (comma seperated value) type file where each line is it's own object/item in your list and each variable is seperated in this instance with a colon. You go through the entire file with the while(getline(file, line)) loop seperating the values from the colons in an easy implemented string function find(character) which returns you the position of the colons in that single line of text from your file. After you find and seperate your data, make sure your numbers are numbers and strings are string. you can switch string to number via stoi function (String TO Integer). All your data is stored in music Collection.
The Output:
Like #Monogeon I would use std::vector<> over an array for storage.
But I think the more idiomatic way to read and write objects in C++ is to define the input and output operators for a class. That way you can stream the objects to not only files but other stream like objects.
This then allows you to use further C++ idioms to manipulate the streams (like std::istream_iterator which reads objects using the input operator (i.e. operator>>).
I added the input and output operators below for you.
Then I create a facade FancyPrintCollection to make printing a collection object in a nice way for a human.
#include <iostream>
#include <string>
#include <fstream>
#include <iomanip>
#include <vector>
#include <iterator>
struct Discography {
std::string title;
int yearPub;
friend std::ostream& operator<<(std::ostream& stream, Discography const& src)
{
return stream << src.title << " " << src.yearPub;
}
friend std::istream& operator>>(std::istream& stream, Discography& dst)
{
// The problem is that "title" could be multiple words.
// We just know that we have a title followed by a number.
// For V1 lets assume "title" is one word
return stream >> dst.title >> dst.yearPub;
}
};
struct Collection {
std::string name;
std::string genres;
int startYear;
int endYear;
Discography records;
friend std::ostream& operator<<(std::ostream& stream, Collection const& src)
{
return stream << src.name << "\n"
<< src.genres << "\n"
<< src.startYear << "\n"
<< src.endYear << "\n"
<< src.records << "\n";
}
friend std::istream& operator>>(std::istream& stream, Collection& dst)
{
std::getline(stream, dst.name);
std::getline(stream, dst.genres);
std::string numberLine;
if (std::getline(stream, numberLine)) {
dst.startYear = std::stoi(numberLine);
}
if (std::getline(stream, numberLine)) {
dst.endYear = std::stoi(numberLine);
}
stream >> dst.records;
stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
return stream;
}
};
struct FancyPrintCollection
{
Collection const& collection;
public:
FancyPrintCollection(Collection const& collection)
: collection(collection)
{}
friend std::ostream& operator<<(std::ostream& stream, FancyPrintCollection const& src)
{
stream << "Name: " << src.collection.name << "\n"
<< "Genre: " << src.collection.genres << "\n"
<< "Start Year: " << src.collection.startYear << "\n"
<< "End Year: " << src.collection.endYear << "\n"
<< "Title: " << src.collection.records.title << " Year Publiszed: " << src.collection.records.yearPub << "\n"
<< "----------------------------------------------------" << "\n" << "\n";
return stream;
}
};
int main()
{
std::ifstream inputMusic("Music.data");
std::vector<Collection> music(std::istream_iterator<Collection>(inputMusic), std::istream_iterator<Collection>{});
for (auto const& m: music) {
std::cout << FancyPrintCollection(m);
}
}
Entry point is int main() so I try summon pwr.GetSalary to cout outside string "Salary" and double value, however program does not print out anything.
So it is base class.
class Employee
{
public:
std::string FirstName;
std::string LastName;
std::string Patronymic;
double Salary;
Employee() {};
explicit Employee(std::string FirstName, std::string LastName,
std::string Patronymic, double Salary)
: FirstName(FirstName), LastName(LastName),
Patronymic(Patronymic), Salary(Salary) {}
bool operator==(Employee other) const
{
if (this->FirstName == other.FirstName &&
this->LastName == other.LastName &&
this->Patronymic == other.Patronymic)
return true;
else
return false;
}
};
An daughter class that inherits base class... Here is wonderful method that shall count a salary and print it out...
class Papersworker : public Employee
{
private:
std::string FirstName;
std::string LastName;
std::string Patronymic;
double Salary;
public:
Papersworker() {};
using Employee::Employee;
const std::string Job = "Papersworker";
std::map<std::string, double> Coefficient =
{
{"Director", 4.2},
{"Papersworker", 1.2},
{"Guardian", 1.5},
{"Programmer", 2.5}
};
void ChangeCoefficient(std::string Job, double NewCoefficient)
{
Coefficient[Job] = NewCoefficient;
}
void ChangeNameSalary(std::string FirstName, std::string LastName, std::string Patronymic, double Salary)
{
this->FirstName = FirstName;
this->LastName = LastName;
this->Patronymic = Patronymic;
this->Salary = Salary;
}
void PrintPapersworker()
{
std::cout << "First name\t" << "Lastname\t" << "Patronymic\t" << "Salary\n" << this->FirstName << "\t\t" << this->LastName << "\t" << this->Patronymic << "\t" << this->Salary << "\n" << std::flush;
for (const auto& i : this->Coefficient)
{
std::cout << i.first << " = " << i.second << ";\t" << std::flush;
}
std::cout << "\n------------------------------------------------------------\n" << std::flush;
}
double GetSalary(double Salary, std::string Job)
{
return Salary * this->Coefficient[Job];
}
};
Wonderful int main()'s part.
int main()
{
Papersworker pwr;
double sr = 0.0;
std::cout << "\nEnter director's salary\t" << std::flush; std::cin >> sr;
std::cout << "\nSalary\t" << pwr.GetSalary(sr, "Director");
return 0;
}
If you see a some bad and need optimization don't mind to reply. ._. I do not understand what is going on there in matter of classes building tricks. https://pastebin.com/p7HXaX80
P. S. My homework forces to use private FirstName,LastName,Patronymic,salary...
P. S. S. However, I use Visual Studio 2022 Preview with newest C++ nowadays.
https://imgur.com/a/N8cDK3n
program does not print out anything
Your program(pastebin link you gave) compiles successfully and prints continuously if you change _getch() to getch() as can be seen here. But for some reason it goes on forever. Since the link that you gave have around 500 lines of code i didn't take a look as to why the condition is not breaking(or if the program has any undefined behavior). Maybe you can narrow down the problem and edit your question again.
Your code will not compile as sr variable is not defined.
Define double sr; before using it in main()'s statement std::cin >> sr; and (at least) the program will compile and interact with the user.
int main() {
Papersworker pwr;
std::cout << "\nEnter director's salary\t" << std::flush;
double sr; // <- your missed variable
std::cin >> sr;
std::cout << "\nSalary\t" << pwr.GetSalary(sr, "Director");
}
Program's prints with input 10:
Enter director's salary 10
Salary 42
All of the private members of Papersworker shadow the public members from Employee
class Papersworker : public Employee {
private:
std::string FirstName;
std::string LastName;
std::string Patronymic;
double Salary;
// ...
};
Try this: Compiler Explorer (Untested ’cause I’m in a rush right now, I’ll look at it when I come back)
Also, be careful with std::map::operator []
// The function which i was required to make was to.string() in the class,Which i had no idea how to make.This is an odd function(not comparing with the math one.)which returns value in two different types of data types i.e(string,integer).The only thing stuck me was assigning a variable after making (string to.string()) function//The return value of function is something like
[age,first_name,last_name,standard](without the square brackets with the commmasin the output)
p.s=need a simpler function without using vector header.
#include <iostream>
#include <sstream>
using namespace std;
class Student{
public :
void set_age(int no){
age_no=no;
}
void set_standard(int no){
std_no=no;
}
void set_first_name(string identity){
name_letter=identity;
}
void set_last_name(string identity2){
last_name_letter = identity2;
}
int get_age(){
return age_num;
}
int get_standard(){
return std_no;
}
string get_first_name(){
return name_letter;
}
string get_last_name(){
return last_name_letter;
}
private :
int age_no;
int std_no;
string name_letter;
string last_name_letter;
};
int main() {
int age, standard;
string first_name, last_name;
cin >> age >> first_name >> last_name >> standard;
Student st;
st.set_age(age);
st.set_standard(standard);
st.set_first_name(first_name);
st.set_last_name(last_name);
cout << st.get_age() << "\n";
cout << st.get_last_name() << ", " << st.get_first_name() << "\n";
cout << st.get_standard() << "\n";
cout << "\n";
cout << st.to_string();
return 0;
}
If you want to create a string with the format age, first_name, last_name, standard then you could do something like
class Student
{
public:
...
std::string to_string() const;
...
};
std::string Student::to_string() const
{
return std::to_string(get_age()) + ", " +
get_first_name() + ", "
get_last_name() + ", "
std::to_string(get_standard());
}
As an aside, I would suggest making all of your getter functions const for example
int get_age() const;
This denotes that the method will not mutate or modify any of the values of the class's member variables.
I am tasked to create a Print function that prints user inputted data that is specific to an object. This print function must use the Get() Function commands I created.
I have googled and looked for similar questions but could not find a way of how I could approach this. How can I create this function my teacher wants?
The object I want to print specifically is book1
My code:
#include <iostream>
#include <string>
#include <cstdio>
using namespace std;
class Book {
public:
void SetTitle(string title_input);
string GetTitle();
void SetAuthor(string& author_input);
string GetAuthor();
void SetCopyRightYear(int copyright_year_input);
int GetCopyRightYear();
void PrintBook();
private:
string title;
string author;
int copyright_year;
};
void Book::SetTitle(string title_input) {
title = title_input;
}
string Book::GetTitle() {
return title;
}
void Book::SetAuthor(string& author_input) {
author = author_input;
}
string Book::GetAuthor() {
return author;
}
void Book::SetCopyRightYear(int copyright_year_input) {
copyright_year = copyright_year_input;
}
int Book::GetCopyRightYear() {
return copyright_year;
}
void Book::PrintBook() {
cout << "Title of Book: " << GetTitle() << endl;
cout << "Author of Book: " << GetAuthor() << endl; // Function is broken FIXME
cout << "Copyright Year: " << GetCopyRightYear() << endl;
}
int main ()
{
string title_input = "";
string author_input = "";
int copyright_year_input = 0;
Book book1;
Book book2;
Book book3;
Book book4;
cout << "Enter the book title: ";
cin >> title_input;
book1.SetTitle(title_input);
cout << book1.GetTitle();
cout << "Enter the author name: ";
cin >> author_input;
book1.SetAuthor(author_input);
cout << "Enter the copyright year: ";
cin >> copyright_year_input;
book1.SetCopyRightYear(copyright_year_input);
cout << PrintBook();
Book.h
#pragma once
#include <string>
class Book
{
public:
Book() = default;
~Book() = default;
const std::string GetTitle() const;
const std::string GetAuthor() const;
const int GetCopyRightYear() const;
void SetTitle(const std::string);
void SetAuthor(const std::string);
void SetCopyRightYear(const int);
void PrintBook();
private:
std::string title;
std::string author;
int copyright_year;
};
Book.cpp
#include "Book.h"
// ------------------------------
#include <iostream>
void Book::SetTitle(const std::string title_input)
{
title = title_input;
}
const std::string Book::GetTitle() const
{
return title;
}
const int Book::GetCopyRightYear() const
{
return copyright_year;
}
const std::string Book::GetAuthor() const
{
return author;
}
void Book::SetCopyRightYear(const int copyright_year_input)
{
copyright_year = copyright_year_input;
}
void Book::SetAuthor(const std::string author_input)
{
author = author_input;
}
void Book::PrintBook()
{
std::string output_str = "";
std::cout << "Title of Book: " << GetTitle() << std::endl;
std::cout << "Author of Book: " << GetAuthor() << std::endl;
std::cout << "Copyright Year: " << GetCopyRightYear() << std::endl;
}
main.cpp
// C++ Libraries.
#include <iostream>
#include <string>
// User classes
#include "Book.h"
// Namespaces
int main()
{
std::string title_input = "";
std::string author_input = "";
int copyright_year_input = 0;
// research dynamic memory allocation.
Book book1;
Book book2;
Book book3;
Book book4;
// user sets book title.
std::cout << "Enter the book title: ";
std::getline(std::cin, title_input);
book1.SetTitle(title_input);
// user sets the authors name
std::cout << "Enter the author name: ";
std::getline(std::cin, author_input);
book1.SetAuthor(author_input);
// user inputs the copyright year.
std::cout << "Enter the copyright year: ";
std::cin >> copyright_year_input;
book1.SetCopyRightYear(copyright_year_input);
// Display the information.
book1.PrintBook();
}
Notes:
When you start using multiple namespaces its easier to see what is what if you dont predefine them.
Const correctness means you and other developers know what can be changed and what cant. It also makes things clearer for the compiler.
std::getline reads the whole line including the blank spaces.
Just a quick note on clarity and understanding. At the moment your code is messy which makes it incredibly hard to debug not only for yourself but for others.
I can't tell on here but just in case, your classes should be in header and source code formatting, with a main source code file for the main function (entry point). Whether or not you've been told this information before I would highly recommend doing some research into basic C++. Just for starters I've put some links below to help. Once your code is neatly formatted you might work out what the problem is.
Happy coding :)
References:
Herb Sutter Cpp Convention 2014 - Simplicity over Complexity:
https://www.youtube.com/watch?v=xnqTKD8uD64
Headers and Includes - C++ formatting:
http://www.cplusplus.com/forum/articles/10627/
Also see the tutorials on cplusplus.com.
I am confused about this problem output result:
I am 10 years old. My name is
Why there is blank string after "My name is"?
#include <iostream>
using namespace std;
class Name {
int first_name;
int last_name;
public:
void setName(int f, int l) {
first_name = f;
last_name = l;
}
int true_name(){
first_name + last_name;
}
};
class Persion {
public:
int age;
Name name;
Persion(){
}
public:
void hello(void){
cout << "I am ";
cout << age;
cout << " years old.";
cout << " My name is " + name.true_name() << endl;
}
};
int main()
{
Persion a;
Name name;
name.setName(10, 2);
a.age = 10;
a.name = name;
a.hello();
return 0;
}
There are a few problems here.
int true_name(){
first_name + last_name;
}
means "add first_name and last_name, discard the result (because you neither returned it nor assigned it to a variable), then return some random result (likely whatever happened to most recently be in the appropriate CPU register)."
Your compiler should have given you warning messages explaining this. For example, GCC gives the following warnings:
warning: statement has no effect
warning: control reaches end of non-void function
Make sure that warnings are enabled for your compiler (for example, in GCC, use -Wall from the command line) and pay attention to the warnings.
You should have used something like this:
int true_name(){
return first_name + last_name;
}
The next problem is in this line:
cout << " My name is " + name.true_name() << endl;
" My name is " is a const char * (pointer to char array, not a std::string class instance), and adding an integer to a pointer means to index that pointer. In this case, you're saying "go true_name() characters into " My name is " and start printing from there." Do this instead:
cout << " My name is " << name.true_name() << endl;
Also, it's "Person," not "Persion."