Adding a class to a map - c++

I am trying to add a class object to a map, this is what I have:
#include<vector>
#include<map>
#include<stdio.h>
#include<string>
#include<iostream>
using namespace std;
class Student{
int PID;
string name;
int academicYear;
public:
Student(int, string, int);
};
Student::Student (int P, string n, int a) {
PID = P;
name = n;
academicYear = a;
}
void createStudent(map<string, Student>);
int main(int argc, char** argv){
map <string, Student> studentList;
createStudent(studentList);
}
void createStudent(map<string, Student> studentList){
int PID;
string name;
int academicYear;
cout << "Add new student-\nName: ";
getline(cin, name);
cout << "PID: ";
cin >> PID;
cout << "Academic year: ";
cin >> academicYear;
Student newstud (PID, name, academicYear);
studentList[name] = newstud; //this line causes the error:
//no matching function for call to
//'Student::Student()'
}
I don't understand why the constructor function is being called there, I thought newstud would already have been constructed from the previous line. Can anyone explain what is happening when I try to add newstud to the map?

Problem 1st
std::map::operator[] will insert new element into container if its not present, using default constructor, which in your case is not present and will probably doesn't make sense even if you provide one.
So use std::map::insert for such scenario
Problem 2nd
Even if you successfully insert using studentList.insert(std::make_pair(name, newstud)); its not going to reflect changes in original map studentList in main ( ) unless you use a reference type, in function definition & declaration of createStudent
So use
void createStudent(map<string, Student>& );

In order to add entries using the function, you should make your parameter studentList pass by reference.
And instead of
studentList[name] = newstud;
use:
studentList.insert(std::make_pair(name, newstud));
Just a suggestion, though.

Related

fill an array of type class inside another class

I am new in c++ recently i started learning poo I want to create a class movies and a class.
directors a class movie should have an array of directors and I want to fill that array from the console. When I run the code it show me the first and second line and stop executing :
enter image description here
this is my code:
#include<iostream>
#include<string>
using namespace std;
class directors{
string name;
string lastname;
public:
directors(){
}
directors(string a,string b){
name=a;
lastname=b;
}
void createdirector(){
cout<<"name of director:"<<endl;
cin>>name;
cout<<"last name:"<<endl;
cin>>lastname;
}
};
class movie{
string name;
directors* director;
public:
film(){
directors* director=new directors[20];
};
void creatmovie(){
cout<<"name of movie"<<endl;
cin>>name;
director[0].createdirector();
}
};
int main(){
movie a;
a.creatmovie();
}
A better way wold be to use std::vector as shown below. The advantage of using a std::vector is that you don't have to worry about manual memory management(like using new and delete explicitly). vector will take care of it(memory management). You can use the below given example as a reference.
#include<iostream>
#include<string>
#include <vector>
class director{
std::string name;
std::string lastname;
public:
director(){
}
//use constructor initializer list
director(std::string a,std::string b): name(a), lastname(b){
}
void createDirector()
{
std::cout<<"Enter name of director:"<<std::endl;
std::cin>>name;
std::cout<<"Enter last name:"<<std::endl;
std::cin>>lastname;
}
void displayDirector() const
{
std::cout << "Firstname: "<<name<<" Lastname: "<<lastname<<std::endl;
}
};
class movie{
std::string name;
std::vector<director> directors; //vector of director objects
public:
//constructor that creates vector directors of size vecSize
movie(size_t vecSize): directors(vecSize)
{
std::cout << "Enter name of movie: "<<std::endl;
std::cin >> name;
//iterate through the vector and call method createDirector on each element
for(director &elem: directors)
{
elem.createDirector();
}
}
void displayMovie()
{
std::cout<<"Movie's name is: "<<name<<std::endl;
//iterate through the vector and call displayDirector on each object
for(const director& elem: directors)
{
elem.displayDirector();
}
}
};
int main(){
movie a(4); //create an object of type movie. Note i have passed 4 as argument you can pass other numbers like 3,2 etc
a.displayMovie();//display movie info
}
Some of the modifications that i made are:
Used constructor initializer list in class director
added a method called displayDirector in class director
added a method called displayMovei in class movie
added a data member called directors that is a std::vector<director> in class movie.
added a constructor for class movie that initializes the data member directors.
removed unnecessary method namedfilm from class movie
not used using namespace std; which is a recommended practice
The output of the above program can be seen here.

How to set a custom variable name through a function argument

So what i am trying to do is basically get the second argument of a function, and making the second argument the name of a variable so i can easily store the users input. Here is my code
`
#pragma once
#include <iostream>
using namespace std;
void askAndStore(string question, string variable)
{
cout << question + " ";
cin >> variable;
}
`
Pass variable by reference:
void askAndStore(string question, string& variable)
{
cout << question + " ";
cin >> variable;
}
string& instead of string. Without using & you'd be passing in a copy of your varaible, using a reference type string& you pass the actual variable in which is then modified by cin >> variable;.
P.S Don't use using namespace std;
You can't do this in C++.
You could have a std::map<std::string, SomeType> that you populate with your read-in names.
#pragma once
#include <iostream>
#include <map>
#include <string>
class Values
{
std::map<std::string, std::string> values;
public:
void askAndStore(std::string question, std::string name)
{
std::cout << question << " ";
std::cin >> values[name];
}
std::string get(std::string name)
{
return values[name];
// or return values.at(name); if name must already exist in values
}
};
int main()
{
Values user;
user.askAndStore("What is your name?", "usersName");
}
That assumes your values are std::strings

C++ Calling overriden functions results in call of base function

I am new to C++ as I made the switch from Java/C#. Can somebody explain why my code doesn't work like I think it should. I have a simple hierarchy of Animal class which is then inherited by Dog and Cat. The only difference between the classes is their virtual method toString() /which obviously returns a string based on which of the classes it is called on/. Okay so I am inputting information and creating the classes with cin and pushing them into a vector of Animals. However when I tried to call their toString() I got the result from the base toString() and not the overriden one. Here is the code at this point:
#include <iostream>
#include <vector>
#include "animal.h"
#include "cat.h"
#include "dog.h"
using namespace std;
int main()
{
vector<Animal> animals;
string type;
string name;
int age;
int weight;
while(cin >> type){
cin >> name >> age >> weight;
if(type == "dog"){
animals.push_back(Dog(name, age, weight);
}
else {
animals.push_back(Cat(name, age, weight);
}
}
for(vector<Animal>::iterator iter = animals.begin(); iter != animals.end();
iter++){
cout << iter -> toString() << endl;
}
return 0;
}
But then after I did some googling I found a suggestion that I should use pointers because of something called object slicing. So then my code turned into this:
#include <iostream>
#include <vector>
#include "animal.h"
#include "cat.h"
#include "dog.h"
using namespace std;
int main()
{
vector<Animal*> animals;
string type;
string name;
int age;
int weight;
while(cin >> type){
cin >> name >> age >> weight;
if(type == "dog"){
Dog tempDog(name, age, weight);
animals.push_back(&tempDog);
}
else {
Cat tempCat(name, age, weight);
animals.push_back(&tempCat);
}
}
for(vector<Animal*>::iterator iter = animals.begin(); iter != animals.end();
iter++){
cout << iter -> toString() << endl;
}
return 0;
}
And now I am getting a compiler error suggesting I should use '->';
Also a side question while I am here I would like to ask. Is there a way of overriding a virtual method from the .cpp file and not the header file where the class is defined. I am recently getting into the oop in c++ and to my idea is that in the header file I just define prototypes of the members of the class and I do the implementation in a different .cpp file.
cout << iter -> toString() << endl;
Is attempting to call a member function of the type of *iter. Since *iter is an Animal* it does not have any member functions. What you need to do is get the value of the iterator and then call its member function with -> like
cout << (*iter)->toString() << endl;
Also note that if you have access to C++11 or higher you can use a ranged based for loop like
for (auto& e : animals)
cout << e->toString() << "\n";
I also changed to "\n" instead of endl as typically you do not need the call to flush so you should only do that when you know you need to.
You also have undefined behavior in your code.
if(type == "dog"){
Dog tempDog(name, age, weight);
animals.push_back(&tempDog);
}
Is going to add a pointer to a automatic object into the vector. When you leave the if block that automatic object get automatically destroyed. After it is destroyed you now have a pointer to an object that no longer exist. The quick fix is to use new to dynamically allocate the object like
if(type == "dog"){
Dog* tempDog = new Dog(name, age, weight);
animals.push_back(tempDog);
}
Now the pointer in the vector will still be valid. Unfortunately now you need to remember to delete all of those pointers when you are done with them. Instead of having to do manual memory management you can use a smart pointer like a std::unique_ptr or std::shared_ptr which will manage the memory for you.

vector wont push class function c++ [duplicate]

This question already has answers here:
Updating vector of class objects using push_back in various functions
(2 answers)
Closed 7 years ago.
I am attempting to make a text adventure sort of game, and I would like to avoid a bunch of conditionals, so I am trying to learn about the classes stuff and all that. I have created several classes, but the only ones that pertain to this problem are the Options class and the Items class. My problem is that I am trying to push_back() a object into a vector of the type of that object's class and it apparently doesn't happen yet runs until the vector is attempted to be accessed. This line is in main.cpp. I have researched on this, but I have not been able to find a direct answer, probably because I'm not experienced enough to not know the answer in the first place.
The program is separated into 3 files, main.cpp, class.h, and dec.cpp.
dec.cpp declares class objects and defines their attributes and all that.
main.cpp:
#include <iostream>
#include "class.h"
using namespace std;
#include <vector>
void Option::setinvent(string a, vector<Item> Inventory, Item d)
{
if (a == op1)
{
Inventory.push_back(d);
}
else {
cout << "blank";
}
return;
}
int main()
{
vector<Item> Inventory;
#include "dec.cpp"
Option hi;
hi.op1 = "K";
hi.op2 = "C";
hi.op3 = "L";
hi.mes1 = "Knife";
hi.mes2 = "Clock";
hi.mes3 = "Leopard!!";
string input1;
while (input1 != "quit")
{
cout << "Enter 'quit' at anytime to exit.";
cout << "You are in a world. It is weird. You see that there is a bed in the room you're in." << endl;
cout << "There is a [K]nife, [C]lock, and [L]eopard on the bed. Which will you take?" << endl;
cout << "What will you take: ";
cin >> input1;
hi.setinvent(input1, Inventory, Knife);
cout << Inventory[0].name;
cout << "test";
}
}
dec.cpp just declares the Item "Knife" and its attributes, I've tried pushing directly and it works, and the name displays.
class.h
#ifndef INVENTORY_H
#define INVENTORY_H
#include <vector>
class Item
{
public:
double damage;
double siz;
double speed;
std::string name;
};
class Player
{
public:
std::string name;
double health;
double damage;
double defense;
double mana;
};
class Monster
{
public:
double health;
double speed;
double damage;
std::string name;
};
class Room
{
public:
int x;
int y;
std::string item;
std::string type;
};
class Option
{
public:
std::string op1;
std::string op2;
std::string op3;
std::string mes1;
std::string mes2;
std::string mes3;
void setinvent(std::string a, std::vector<Item> c, Item d);
};
#endif
Any help would be greatly appreciated! I realize that the whole structure may need to be changed, but I think that this answer will help even if that may be the case.
My problem is that I am trying to push_back() a object into a vector of the type of that object's class and it apparently doesn't happen yet runs until the vector is attempted to be accessed.
it happen but only inside your setinvent method:
void Option::setinvent(string a, vector<Item> Inventory, Item d)
^^^^^^^^^^^^ - passed by value
Inventory is passed by value which means it is a local vector variable in setinvent function. If you want to modify vector from main function, make it a reference:
void Option::setinvent(string a, vector<Item>& Inventory, Item d)
^^^^^^^^^^^^ - passed by reference, modifies vector from main
now Inventory is local reference variable. Also dont forget to change setinvent declaration in header file.

only one function from class intilized in main function of c++

I just wrote a simple program that has two functions in a class. Problem is when I called them from main(), only the first function executes and the program terminates without calling the second function.
#include <stdio.h>
#include <iostream>
using namespace std;
class exp{
public:
string name;
public:
string fun1(){
cout<<"please enter value for first function ";
cin>>name;
cout<<"yourname from first function is ";
cout<<name;
return 0;
}
string fun2(){
cout<<"Please enter value for second function ";
cin>>name;
cout<<"yourname from second function is ";
cout<<name;
return 0;
}
};
int main(){
exp b1,b2;
cout << b2.fun1();
cout << b1.fun2();
}
The output is
please enter value for first function preet
yourname from first function is preet
You are returning 0 while the return type is string. Constructing a std::string from a null pointer is not allowed. You could use return ""; instead.
Here, try this
#include <stdio.h>
#include<iostream>
using namespace std;
class exp
{
private: // changed from public to private
string name;
public:
int fun1() // changed from string to int
{
cout<<"\nplease enter value for first function ";
cin>>name;
cout<<"\nyourname from first function is ";cout<<name<<endl;
return 0;
}
int fun2() // changed from string to int
{
cout<<"\nPlease enter value for second function ";
cin>>name;
cout<<"\nyourname from second function is ";
cout<<name<<endl;
return 0;
}
};
int main()
{
exp b1,b2;
b2.fun1(); // removed cout
b1.fun2(); // removed cout
}
The problem was you were using cout inside your functions, yet you were also calling them inside a function, that is cout<<b2.fun1();. This is not a good practice.
There was also the problem that the type of your functions were string, but they were returning an integer.
You had also made name as public which just defies the use of OOP. So I made it private.
Cheers......Hope this solves your Problems.. :)