Dynamically create objects in c++? - c++

Take a look at this code, it has a class that, when a new object is created, will give it a random number for 'lvl' between 1 and 100. After the class, I define some objects using class instances.
#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
class newPokemon {
public:
int lvl;
newPokemon() {
lvl = (rand() % 100 + 1);
};
void getLevel() {
cout << lvl << endl;
};
};
newPokemon Gengar;
newPokemon Ghastly;
newPokemon ayylmao;
};
What I want to do next is allow the use to define new pokemon (objects) by asking them for a name. This means, however, I need to create objects dynamically. For example,
Program asks user for a name
Name is then saved as an object from the class newPokemon
Program can use that name to run other functions from the class, like getLevel.
How am I able to do this? I, of course, get that I can't do it like the hard coded ones, as I cannot reference user input as a variable name, but is there some way to do what I am asking by manipulating pointers or something?

Use std::map to hold your objects according to their names:
std::map<std::string, newPokemon> world;
You must make sure that your objects get added to the map immediately after being created.
std::string name;
... // ask the user for a name
world[name] = newPokemon();
std::cout << "Your level is " << world[name].getLevel() << '\n';

You probably just want each Pokemon to have a name property (member variable/field). Just make a bunch of Pokemon with the name filled in.

Related

Attempting to Reference a Class Object Within Another Class to Avoid a 2nd Instance of that Class

1. Explanation of error and my logic
I am having trouble figuring out why using a referenced object from one class into a separate class is not working the way I thought it would. I have included streamlined code below for this example with a Main.cpp and 2 other classes, named InventoryStorage and ShoppingExperience.
The InventoryStorage class stores names from a .txt file into a vector, and has a typical getter that I can make an object for in Main.cpp to output these names: invStObj.getFileInvData(i)
My problem is that I wish to use this getter in several other classes as well, WITHOUT making a new instance of the object, InventoryStorage invStObj; that was made in Main.cpp
Instead, I attempted to make a reference for this object, InventoryStorage& invStRefObj = invStObj; that my other class ShoppingExperience.cpp will use in order to utilize the getFileInvData() function in this class as well.
When I run this code, it should output the desired output but instead, the actual output is cut short when it reaches the Item List in Inventory part. My reference object in my 2nd class will not work with the getter function from the 1st class properly.
cout << invStObj.getFileInvData(i) << endl; that is in Main.cpp properly outputs "test items" followed by the names
cout << invStRefObj.getFileInvData(i) << endl; from ShoppingExperience class just outputs "Item List in Inventory" and then errors without outputting any names
Desired Output.................................................... Actual Output
test items test items
book book
movie movie
food food
game game
Item List in Inventory Item List in Inventory
book
movie
food
game
I receive an error, "vector subscript out of range" because my ShoppingExperience.cpp is trying to use the getter with a new empty vector. Using a reference of the object did not seem to protect it from creating a new instance of that class which is what I was trying to prevent in the first place.
Please refer to my code located below for clarification
2. Question:
Is it possible to reference to an object from another class similar to my failed attempt? Is there some alternate format or function that I can use to achieve this? I would like Main.cpp and my ShoppingExperience.cpp to use the same object and class instance for the InventoryStorage class functions
3. InventoryStorage.h, InventoryStorage.cpp, Main.cpp, ShoppingExperience.h, ShoppingExperience.cpp are shown below in their entirety for citation
InventoryStorage.h
#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
using std::string;
using std::vector;
class InventoryStorage
{
public:
InventoryStorage();
void storeFileInvData(string); //opens and stores file names to vector, invDataCl
string getFileInvData(int); //returns names from vector, invDataCl
private:
string fileNameCl;
string lineCl;
vector<string> invDataCl;
};
InventoryStorage.cpp
#include "InventoryStorage.h"
InventoryStorage::InventoryStorage() {
}
void InventoryStorage::storeFileInvData(string fileNameTmp) {
fileNameCl = fileNameTmp;
std::ifstream openInvFileCl;
openInvFileCl.open(fileNameCl);
while (getline(openInvFileCl, lineCl, ',')) {
lineCl.erase(remove(lineCl.begin(), lineCl.end(), ' '));
invDataCl.push_back(lineCl);
}
}
string InventoryStorage::getFileInvData(int invDataTmp) {
return invDataCl[invDataTmp];
}
Main.cpp
#include <iostream>
#include "InventoryStorage.h"
#include "ShoppingExperience.h"
using namespace std;
int main() {
InventoryStorage invStObj; //obj to create instance of InventoryStorage class
InventoryStorage& invStRefObj = invStObj; //reference to obj that I can use in other classes, so that I can use same instance
invStObj.storeFileInvData("inventoryData.txt");
cout << "test items" << endl;
for (int i = 0; i < 4; i++) {
cout << invStObj.getFileInvData(i) << endl; //object and getter work fine in main, output names
}
cout << "\n";
ShoppingExperience shopExpObj; //program errors, ShoppingExperience class will not out any names
//ShoppingExperience class uses the reference object unsuccessfully
return 0;
}
ShoppingExperience.h
#pragma once
#include <iostream>
using std::cout;
using std::endl;
class ShoppingExperience {
public:
ShoppingExperience();
private:
};
ShoppingExperience.cpp
#include "ShoppingExperience.h"
#include "InventoryStorage.h"
ShoppingExperience::ShoppingExperience() {
InventoryStorage invStRefObj; //trying to reference first instance of object for InventoryStorage class inside ShoppingExperience class
cout << "Item List in Inventory" << endl; //only outputs "Item List in Inventory"
for (int i = 0; i < 4; i++) {
cout << invStRefObj.getFileInvData(i) << endl;
}
//no names are outputted, then errors and program stops
} //vector subscript out of range (the vector is empty)
//doesn't appear to be using object of same instance like I thought the referenced object would ensure
InventoryStorage invStRefObj is a completely new object unrelated to the reference declared in main. You need to pass the object via reference to the constructor of ShoppingExperience:
In main:
ShoppingExperience shopExpObj(invStObj);
In the header:
class ShoppingExperience {
public:
ShoppingExperience(InventoryStorage& invStRefObj);
private:
};
In the cpp:
ShoppingExperience::ShoppingExperience(InventoryStorage& invStRefObj) {
cout << "Item List in Inventory" << endl; //only outputs "Item List in Inventory"
for (int i = 0; i < 4; i++) {
cout << invStRefObj.getFileInvData(i) << endl;
}
}
Note that it's not necessary to create a reference in main. You can just pass an object directly to a function/method/constructor that expects a reference.
You should avoid putting using namespace in header files as these will then apply to all places that header is included.

storing and working with multiple objects of the same class in c++

I'm sure there is a simple solution for this but i'm having trouble working out what the best option is. Say the for example I have a class called entity that looks like this:
class Entity
{
public:
int health;
int strength;
};
This is obviously a very simple class but my problem is when it comes to creating each object. If I am trying to make a game or whatever where I have lots of different types of entity's with different values for health and strength. What is the best way to organize the declaration of all these variables so that I don't end up with something that looks like this:
Entity cat;
cat.health = 6;
cat.strength = 10;
Entity dog;
dog.health = 10;
dog.strength = 15;
Entity wolf;
wolf.health = 17;
wolf.strength = 25;
This is already looks kind of messy but it gets even worse with more objects or objects with more variables to declare. What is the best way around something like this i've been struggling to figure it out.
The answer you're looking for is encapsulation. Instead of having all your variables be public and assigning values to them one-by-one, you could try something like this:
class Entity
{
private: int health;
private: int strength;
public:
Entity(int h, int s) //constructor
{
health = h;
strength = s;
}
};
and then calling it like so:
Entity cat(15,16);
You could also use separate setter functions but a constructor is the easiest way to go.
As long as the Entity class is kept simple and doesn't require a custom constructor for other purposes, you can initialize the objects like this:
Entity cat { .health = 9, .strength = 2 };
Entity dog { .health = 1, .strength = 3 };
which might be more readable compared to the constructor method because you keep the variable names.
To store many objects you want to use container. As your objects are identified by names, dog, cat and wolf, a map can be used:
#include <string>
#include <map>
#include <iostream>
struct Entity {
int health;
int strength;
};
int main() {
std::map<std::string,Entity> entities;
entities["cat"] = {6,10};
entities["dog"] = {10,15};
entities["wolf"] = {17,25};
for (const auto& e : entities){
std::cout << e.first << " health: " << e.second.health << " strength: " << e.second.strength << "\n";
}
}
Output:
cat health: 6 strength: 10
dog health: 10 strength: 15
wolf health: 17 strength: 25
Using strings as keys is not necessarily the best option, its just to demonstrate what can be done. For example if the number of entities is fixed you could use an enum entity_type { dog,cat,wolf} as key. Alternatively the name could be a member of Entity and you can use a std::vector<Entity> to store them.

C++ - using std::list, how do you print a linked list of an object's private members?

It works for when I make Unit's members public. Changing the variables to private, how do I access/print them?
My professor hasn't taught the method of iterating through a linked list of objects (in this case ) and how to access that object's private members. Do I do implement getters and setters? I'm really lost since I'm pretty new at linked lists and using the list library.
#include <iostream>
#include <list>
#include <string>
using namespace std;
class Unit {
private:
string name;
int quantity;
public:
Unit(string n, int q){
name = n;
quantity = q;
}
};
void showTheContent(list<Unit> l)
{
list<Unit>::iterator it;
for(it=l.begin();it!=l.end();it++){
//
cout << it->name << endl;
cout << it->quantity << endl;
// cout << &it->quantity << endl; // shows address
}
}
int main()
{
// Sample Code to show List and its functions
Unit test("test", 99);
list<Unit> list1;
list1.push_back(test);
showTheContent(list1);
}
The private specifier's goal is to prevent the access to the members from outside of this class. Your design of the Unit class is ridiculous because you hide the members from everybody and you don't use them inside of this class either.
You may open the access the members, you may add getters/setters, implement the Visitor pattern -- there are many options. The simplest is to open the access (make everything public): you should judge based on the task that your professor gave you.
By the way, in your showTheContent function you are making the full copy of the list, which you are probably not planning to do. Use a const reference instead:
void showTheContent(const list<Unit>& l)

Set and get member functions manipulation of data members

So I'm an newbie to programming and I have encountered a
case for which I suppose qualifies as an authentic question
in this awesome forum. Is there a way to write statements inside my get functions so that I can obtain all the changed data member values without having to create multiple get functions
for each data member?
Regards
I am practicing building programs which are easy to maintain by localizing the effects to a class's data members by accessing and manipulating the data members through their get and set functions. In this regard I have two data members for which I wish to change. After compiling, the set functions works well by changing the values but the get functions can only return one of the data member values at a time.
class GradeBook
{
public:
void setCourseName(string code,string name)
{
CourseCode = code;
CourseName = name;
}
string getCourseName()
{
return CourseCode;
return CourseName;
}
void displayMessage()
{
cout<<"Welcome to the GradeBook for: \n" <<getCourseName()
<<endl;
}
private:
string CourseName;
string CourseCode;
};//end class GradeBook
After compiling and running the program, the program outputs the CourseCode but the CourseName doesn't get displayed. I had to create two get functions each to obtain the two data members. I don't want to have 2 get functions to obtain the data member values. I just want to use one get function to keep the code at minimum.I wish to use one get function to return two values for each data member. I have already tried using one return statement and separated the data members with a comma.
Your idea of using return twice cannot work, the first return will return control to the caller and the second will never be executed. You should have got warning about it from your compiler.
I believe that an initial solution could be to use std::pair (docs: https://en.cppreference.com/w/cpp/utility/pair), see snippet below.
NOTE: using namespace std; (which is most likely what you are doing in the code you do not show), is a bad practice, consider using the fully qualified name
#include <string>
#include <utility>
#include <iostream>
//Bad practice, I added it only to keep differences with OP code small
using namespace std;
class GradeBook
{
public:
void setCourseName(string code,string name)
{
CourseCode = code;
CourseName = name;
}
std::pair<string, string> getCourseName()
{
return {CourseCode, CourseName};
}
void displayMessage()
{
//only in C++17
auto [code, name] = getCourseName();
cout<<"Welcome to the GradeBook for: \n" << code << " - " << name
<<endl;
}
private:
string CourseName;
string CourseCode;
};//end class GradeBook
Note that auto [code, name] is a feature called structured binding, available only in C++17, if you have an older compiler, you have to return a std::pair<std::string, std::string> and access its elements using the member variables first and second.
Now, std::pair is good for this contrived example, but, for your case, you might want to consider doing something a bit more readable, because the elements of the pair have the same type so the user of your library will have difficulties remembering what is the first and second element. So you might want to use a custom-made struct with some more meaningful names.
#include <string>
#include <utility>
#include <iostream>
//Bad practice, I added it only to keep differences with OP code small
using namespace std;
struct CourseCodeAndName{
std::string code;
std::string name;
};
class GradeBook
{
public:
void setCourseName(string code,string name)
{
CourseCode = code;
CourseName = name;
}
CourseCodeAndName getCourseName()
{
return {CourseCode, CourseName};
}
void displayMessage()
{
auto codeAndName = getCourseName();
cout<<"Welcome to the GradeBook for: \n" << codeAndName.code << " - " << codeAndName.name
<<endl;
}
private:
string CourseName;
string CourseCode;
};//end class GradeBook
See this example. Alternatively you can use std::tuple.
class GradeBook
{
/* ... */
public:
std::pair<std::string, std::string> get(){
return std::make_pair(CourseName, CourseCode);
}
};
int main()
{
GradeBook book1("Hello","World")
auto result = book1.get();
cout << result.first << result.second;
}
If you write:
return x,y;
or:
return x;
return y;
You should know that in first case you get the last value (you get y), and in second case you get the value of first return (you get x, because as soon as compiler see return, function will return the value, and then function will go in epilogue state (cleaning of stack memory assigned to function, both inline and non-inline function).
And about the use of get function it's normal. If you want to use the value to do something of logic (not to display), yes you should use a lot of get function. Instead if you want to display the values, use a void function, for example "void printData();", and inside it write code to print data. You probably setted the class variables as private (following the encapsulation rules) so you will have access to them inside the print function.

Creating a vector of a class type inside another class

I have run into an issue concerning classes. My goal is to model some population with a certain number of individuals possessing different characteristics. Concerning the scope, I have something like this:
-individual.h --> contains a class called individual:
class Individual
{
public:
//some characteristics, I will use random values here
double a = 14.0;
double b = 6.0;
}
-population.h --> contains a class called population:
class Population
{
public:
std::vector<Individual> populationVector;
}
What I thus want to do is create a population vector that contains a certain number of my class individuals, using something like this.
vector<Individual> populationVector( 100, Individual() );
When I call populationVector in my main.cpp the compiler does not give an error. When I consecutively try to use a simple loop to read out the vector contents to the screen, it gives an
operand type error
(and yes, I included the relevant libraries in each file).
EDIT: loop
for(int i = 0; i < populationVector.size(); i++)
std::cout << populationVector[i] << "\n";
populationVector[i] returns an object of type Individual. You didn't define an overload for operator<<. That's the reason why you get an error at
std::cout << populationVector[i] << "\n";
The compiler doesn't know how to print objects of your class to console. You have to implement a function like
std::ostream &ostream(std::ostream &os, const Individual& inv) {
return os << inv.a << " " << inv.b << "\n";
}
You can not 'call your population vector'. You have to create an object of Population and then access its member.
#include "Population.h"
int main()
{
Population pop;
pop.populationVector.insert(pop.populationVector.begin(), 100, Individual() );
}
But normally you do not want to expose your internal members to the calling code.
So populationVector should be private or protected and Population should offer functions to ineract with the individuals.