vector wont push class function c++ [duplicate] - c++

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.

Related

C++ Destructor: cannot access private member declared in class

I am trying to create a simple program in C++ that creates lists of movies using 2 classes: Movie, which contains details of one movie, and Movies, which contains a name and a vector of Movie objects. The whole point is that the user should only interact with the class Movies, therefore I have chosen to make all the members (both data and methods) of the Movie class private.
I keep getting the following error if I let Movie::~Movie() as it is, but if I comment it in both .h and .cpp, it works just fine.
I have explicitly made Movies class a friend of Movie class, so it can access all its members.
error from Visual Studio Community 2019
Movie.h:
#pragma once
#include<iostream>
#include<string>
class Movie
{
friend class Movies;
private:
std::string name;
std::string rating;
int watchedCounter;
int userRating;
std::string userOpinion;
// methods also private because the user should only interact with the Movies class, which is a friend of class Movie
std::string get_name() const;
Movie(std::string nameVal = "Default Name", std::string ratingVal = "Default Rating", int watchedCounterVal = 0, int userRatingVal = 0, std::string userOpinionVal = "");
~Movie();
};
Movie.cpp:
#include "Movie.h"
// Name getter
std::string Movie::get_name() const
{
return this->name;
}
///*
// Destructor
Movie::~Movie()
{
std::cout << "Movie destructor called for: " << this->name << std::endl;
}
//*/
// Constructor
Movie::Movie(std::string nameVal, std::string ratingVal, int watchedCounterVal, int userRatingVal, std::string userOpinionVal) : name{ nameVal }, rating{ ratingVal }, watchedCounter{ watchedCounterVal }, userRating{ userRatingVal }, userOpinion{userOpinionVal}
{
std::cout << "Movie constructor called for: " << name << std::endl;
}
Movies.h:
#pragma once
#include<iostream>
#include<vector>
#include "Movie.h"
class Movies
{
private:
std::string listName;
std::vector<Movie> vectOfMovies;
static int listNumber;
public:
Movies(std::string listNameVal = "Default User's Movie List ");
~Movies();
std::string get_listName() const;
void addMovie(Movie m);
};
Movies.cpp:
#include<string>
#include "Movies.h"
int Movies::listNumber = 0;
// Constructor
Movies::Movies(std::string listNameVal) : listName{listNameVal}
{
++listNumber;
listName += std::to_string(listNumber);
std::cout << "MovieS constructor called for: " << listName << std::endl;
}
// Destructor
Movies::~Movies()
{
std::cout << "MovieS destructor called for: " << listName << std::endl;
}
std::string Movies::get_listName() const
{
return this->listName;
}
//Add movie to list of movies
void Movies::addMovie(Movie m)
{
this->vectOfMovies.push_back(m);
}
And the main .cpp file:
#include <iostream>
// #include "Movie.h"
#include "Movies.h"
int main()
{
Movies moviesObj;
moviesObj.get_listName();
return 0;
}
If the constructor/destructor is declared as private, then the class cannot be instantiated. If the destructor is private, then the object can only be deleted from inside the class as well. Also, it prevents the class from being inherited (or at least, prevent the inherited class from being instantiated/destroyed at all).
The use of having destructor as private:
Any time you want some other class to be responsible for the life cycle of your class' objects, or you have reason to prevent the destruction of an object, you can make the destructor private.
For instance, if you're doing some sort of reference counting thing, you can have the object (or manager that has been "friend"ed) responsible for counting the number of references to itself and delete it when the number hits zero. A private dtor would prevent anybody else from deleting it when there were still references to it.
For another instance, what if you have an object that has a manager (or itself) that may destroy it or may decline to destroy it depending on other conditions in the program, such as a database connection being open or a file being written. You could have a "request_delete" method in the class or the manager that will check that condition and it will either delete or decline, and return a status telling you what it did. That's far more flexible that just calling "delete".
So, I suggest that you could declare ~Movie(); as public. Then, the problem will be solved.

Subclass member variable as argument for main-class constructor in initialization list = crash?

Very new to programming so forgive me for maybe not seeing something obvious.
Basically I just want to know why all three codes do compile, but the resulting executables CRASH in cases TWO and THREE
(I marked the differences with comments)
ONE - compiles
#include <iostream>
#include <string>
using namespace std;
string testrace = "dog"; //defining it only globally
class Attributes {
public:
Attributes (string race){
if (race == "human"){
intelligence = 10;}
else if (race == "dog"){
intelligence = 4;}
}
int intelligence;
};
class Dalmatian: public Attributes{
public:
// but NOT locally
Dalmatian (): Attributes{testrace} { //using it as an argument
cout << "do i even arrive here" << endl;
}
};
int main() {
Dalmatian bob;
cout << bob.intelligence << endl;
}
TWO - crashes
#include <iostream>
#include <string>
using namespace std;
class Attributes {
public:
Attributes (string race){
if (race == "human"){
intelligence = 10;}
else if (race == "dog"){
intelligence = 4;}
}
int intelligence;
};
class Dalmatian: public Attributes{
public:
string testrace = "dog"; //only defining it locally
Dalmatian (): Attributes{testrace} { //using it as argument
cout << "do i even arrive here" << endl;
}
};
int main() {
Dalmatian bob;
cout << bob.intelligence << endl;
}
THREE - crashes
#include <iostream>
#include <string>
using namespace std;
string testrace = "dog"; //defining it globally
class Attributes {
public:
Attributes (string race){
if (race == "human"){
intelligence = 10;}
else if (race == "dog"){
intelligence = 4;}
}
int intelligence;
};
class Dalmatian: public Attributes{
public:
string testrace = "dog"; // AND locally
Dalmatian (): Attributes{testrace} { //using it as argument
cout << "do i even arrive here" << endl;
}
};
int main() {
Dalmatian bob;
cout << bob.intelligence << endl;
}
What I am looking for, of course, is a working alternative to example TWO.
However I am also interested in an explanation why all of the three pieces of code will compile fine, but executables resulting from 2 and 3 will crash.
EDIT: I do know that examples ONE and THREE don't make sense, I used them for demonstrational purposes. (Also fixed my wording, compiler did fine, executable crashed);
EDIT2: I do, of course, realize that I could just replace "testrace" with ""dog"", but for easier transferability to other subclasses, I would prefer a solution that lets me use a variable argument for Attributes(), that I can vary depending on the subclass, that is invoking the main class.
First off when you have
...
string testrace = "dog";
Dalmatian (): Attributes{testrace}
...
testrace will hide the global testrace as class members supersede global variables when you are in class scope. This means both example two and three use the same variable, the class member variable.
The reason two and three crash because you are trying to use a variable that has no been constructed before. When you get to
Dalmatian (): Attributes{testrace}
testrace has not yet been constructed. Even though you have string testrace = "dog"; in the class body that initialization doesn't happen until after Attributes{testrace} is called. So Attributes (string race) gets a uninitialized string and using it is undefined behavior and also causes your crash.
The problem is that at the time that Attributes is constructed the testrace variable is yet uninitialized, and accessing it gives you undefined behavior.
You can simply fix this by writing
Dalmatian (): Attributes{"dog"} { //using it as argument
cout << "do i even arrive here" << endl;
}
See the working code here.

C++ How to get a specific object in a class

I want to get a specific object in a class in C++. I looked into multiple sites and it seems my question is unique. Okay here's my code.
In House.h
#include <string>
using namespace std;
class House
{
string Name;
int Health;
public:
House(string a, int h);
void GetHouseStats();
void DamageHouse(int d);
~House();
};
in House.cpp
#include "House.h"
#include <iostream>
House::House(string a, int h)
{
Name = a;
Health = h;
}
void House::DamageHouse(int d) {
Health -= d;
cout << "Your " << Name << " has " << Health << " left."<<endl;
}
void House::GetHouseStats() {
cout << Name<<endl;
cout << Health;
}
House::~House()
{
}
in Source.cpp
#include <iostream>
#include "House.h"
using namespace std;
int main()
{
House Kubo("Bahay Kubo", 2);
Kubo.DamageHouse(1);
}
I have House Kubo as my first object. I would like to save the person's houses into a file but my problem is How can I pass the object's name into the function so that save its data into a file? I can manually place the Kubo and do so as
PlayerHouse = Kubo.Name;
But what if I don't know which house I should save? Like instead of typing down
PlayerHouse = Apartment.Name;//2nd house
PlayerHouse = Modern.Name;//3rd house
Can I use an function argument to place the object's name into PlayerHouse? Like this
void SetHouseName(type object){
PlayerHouse = object.Name;
}
Few ways in which this can be done .. is keeping all created object in a container and then access access the container to get the object in and pass it a function which will write it to a file .
Also if you do not want to maintain the container what you have mentioned about using the function will also work fine
Of course, but if you are going to save the Name of the house anyway, why don't you just ask for a std::string in the first place and then pass the Name to that function?
void SetHouseName(std::string name)
{
PlayerHouse = name;
}
If this is outside your House class you need to create a method to expose the Name member of House though, or just make it public.
To answer your initial question, just as how you would pass built-in types, you can do the same for your House type :
void SetHouseName(House house)
{
PlayerHouse = house.Name;
}

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.

Overriding virtual function not working, header files and c++ files

We have a parent class called Student. We have a child class: StudentCS.
Student.h:
#include <iostream.h>
#include<string.h>
#include<vector.h>
#include "Course.h"
class Course;
class Student {
public:
Student();
Student(int id, std::string dep, std::string image,int elective);
virtual ~Student();
virtual void Study(Course &c) const; // this is the function we have a problem with
void setFailed(bool f);
[...]
};
Student.cpp:
#include "Student.h"
[...]
void Student::Study(Course &c) const {
}
And we have StudentCS.h:
#include "Student.h"
class StudentCS : public Student {
public:
StudentCS();
virtual ~StudentCS();
StudentCS (int id, std::string dep, std::string image,int elective);
void Study(Course &c) const;
void Print();
};
And StudentCS.cpp:
void StudentCS:: Study (Course &c) const{
//25% to not handle the pressure!
int r = rand()% 100 + 1;
cout << r << endl;
if (r<25) {
cout << student_id << " quits course " << c.getName() << endl;
}
}
We create student in the main:
Student *s;
vector <Student> uniStudent;
[...]
if(dep == "CS")
s = new StudentCS(student_id,dep,img,elective_cs);
else
s = new StudentPG(student_id,dep,img,elective_pg);
uniStudent.push_back(*s);
Then we call to study, but we get the parent study, and not the child!
Please help!
The code compiles but when run and called on the uniStudent.Study() it uses the parent and not the child
EDIT: after your edit the problem is clear.
The problem is that you are storing base concrete objects in a STL container. This creates a problem called object slicing.
When you add a student to a vector<Student>, since the allocator of the vector is built on the Student class, every additional information on derived classes is just discarded. Once you insert the elements in the vector they become of base type.
To solve your problem you should use a vector<Student*> and store directly references to students in it. So the allocator is just related to the pointer and doesn't slice your objects.
vector<Student*> uniStudent;
...
uniStudent.push_back(s);
uniStudent[0]->study();
Mind that you may want to use a smart pointer to manage everything in a more robust way.