Creating a vector of objects - c++

vector <Population> obj;
int num_of_cities = 0;
cout<<"Enter the number of cities"<<endl;
cin>>num_of_cities;
for( int x = 0; x < num_of_cities ; x++)
{
cout<<"Enter population for city #"<< x + 1 <<endl;
cin>>populate;
obj[x].setPopulation(populate);
.....
Im trying to make a vector of objects. Basically the user will input the amount of cities and the program should create an object for each city. That way information on each city can be entered. I believe there is a problem with the syntax because once I put a value for populate, the program crashes. Any one can help ?

The following line is the problem:
obj[x].setPopulation(populate);
You are trying to access the object at index x but your vector is actually empty.
To solve this, there is 2 solutions:
You should create a Population object and push_back to your vector at each loop iteration
Example:
//...
for( int x = 0; x < num_of_cities ; x++)
{
cout<<"Enter population for city #"<< x + 1 <<endl;
cin>>populate;
Population pop;
pop.setPopulation(populate)
obj.push_back(pop);
}
//...
Or you initialize your vector with a size only when you know the number of cities: vector <Population> obj (num_of_cities);
Example:
//...
cin>>num_of_cities;
vector <Population> obj (num_of_cities); // move your vector declaration here
for( int x = 0; x < num_of_cities ; x++)
//...

obj[x].setPopulation(populate);
here you are trying to access an element which is out-of-bound, since the vector obj has no content yet.
A way to make this work would be to call
obj.resize(num_of_cities)
before the for loop.
A more general approach (which would work if you do not know beforehand how many elements you will have, but which is slower in this case), would be creating a Population object, and then pushing it to the vector:
Population p;
p.setPopulation(populate);
obj.push_back(p);

While currently available answers correctly identify the source of the problem at hand - access to empty vector - they fail to set the right example of using the vector in a given scenario. They either suggest a push_back of pre-constructed object - thus calling a copy-construcor unnecessarily - or demand a presence of default constructor, with a side effect of exra assignment.
The most elegant solution would be following:
Make sure your Population has a constructor which accepts population size and sets internal member accordingly (likely to be const int):
Population::Population(int habitants) : habitants(habitants) { }
Than, use emplace_back to insert an object without calling any other constructors:
obj.emplace_back(populate);

The following code will let you make a vector of city objects that you can then populate with meaningful data. First, you need to define a City class that can set and get the various data items. The code will compile and run but it is a limited version of what you might want to accomplish.
#include<iostream>
#include<vector>
#include<string>
using namespace std;
class City {
public:
City() {}
~City() {}
void setPopulation(int& pop) { m_pop = pop; }
int getPopulation() const { return m_pop; }
void setName(const string& name) { m_name = name; }
string getName() const { return m_name; }
private:
string m_name{ "" };
int m_pop{ 0 };
};
vector<City> cities(0);
int num_of_cities = 0;
int main() {
do {
cout << "Enter number of cities: ";
cin >> num_of_cities;
} while (num_of_cities < 1);
cities.resize(num_of_cities);
int val{ 0 };
string nam{ "" };
for (int i = 0; i < cities.size(); i++) {
cout << "Enter name of city: ";
cin >> nam;
cities[i].setName(nam);
cout << "Enter population for city: ";
cin >> val;
cities[i].setPopulation(val);
}
system("pause");
return 0;
}

Related

C++ Trouble adding objects to a list

I am having trouble adding objects to a list.
I want to make a List of Persons, and I know the size of the list is fixed at 5 people.
Each Person has an age (int) and a gender (string).
I want to add the Persons to the List, but I don't know how, I've only worked with integers now that I think of it.
Below is what I have so far.
The random age and gender is working, however clunky that is.
I'm thinking instead of creating the Persons as I did, maybe somehow I should create them dynamically in a for loop which will somehow generate the age and gender per loop iteration? Maybe the list should be pointers to the Person objects.
#include <iostream>
#include <list>
#include <memory>
using namespace std;
class Person {
private:
const int OLDEST_AGE = 100;
const int YOUNGEST_AGE = 1;
int age;
string gender;
public:
Person()
{
age = generateAge();
gender = generateGender();
}
// Person: generate random age for Person, from 1-100
int generateAge() {
int randomAge;
randomAge = rand() % (OLDEST_AGE - YOUNGEST_AGE + 1) + YOUNGEST_AGE;
return randomAge;
};
// Person: generate random gender for Person, Male or Female
string generateGender() {
int genderNumber;
genderNumber = rand() % (1 - 0 + 1) + 0;
if (genderNumber == 1)
return "Male";
else
return "Female";
};
void getStats() {
cout << "Person Age: " << age << endl;
cout << "Person Gender: " << gender << endl;
};
};
int main()
{
Person P1, P2, P3, P4, P5;
// Just to see if the objects are created
P1.getStats();
P2.getStats();
P3.getStats();
P4.getStats();
P5.getStats();
list<Person> myList;
list<Person>::iterator IT;
for (int i = 1; i <= 5; i++)
//don't know how to add each Person to the list
myList.push_back(P1);
cout << "myList contains: ";
for (IT = myList.begin(); IT != myList.end(); IT++)
// similar to above, how do I get the list to print each object's stats
P1.getStats();
cout << endl;
return 0;
}
Using vector would be better in your case if you want to add a lot of elements one after the other as specified in another response to another question comparing list and vector.
Back to the question, as some comments specified, declaring a variable for each person is not a good practice. What you could do instead is to populate your list with a loop like so:
for(int i = 0; i < 5; i++)
myList.push_back(Person());
Then to access the objects you would just loop through the list again wherever you need to.
for(int i = 0; i < 5; i++)
myList[i].getStats();
You can create a vector, and run through a loop where you instantiate the person, and then push them into the vector. This way, you won't need to create separate person variables like p1, p2, etc., and your vector would hold all the "Person" objects.
vector<Person> people;
for (int i = 0; i < 5; i++) {
people.push_back(Person());
}
for (Person person : people) {
person.getStats();
}

How to initialize an array in a constructor c++

I need help with this code.
What I want is to make a parametric constructor and initialise/set the value of array in it.
Question: Make a class with arrays of integers and initialise it in a constructor. Then find the smallest and largest numbers using functions.
But I am stuck at how to initialise the array in the constructor.
I want to take data input in both ways
(1) By user, using cin
(2) By giving my own values
class Numbers
{
int Arr[3];
public:
Numbers() //default constructor
{
for (int i=0 ; i<=2 ; i++)
{
Arr[i]=0;
}
}
Numbers(int arr[]) //parameteric constructor
{
for (int i=0;i<=2;i++)
{
Arr[i]=arr[i];
}
}
};
int main()
{
int aro[3] = {0,10,5};
Numbers obj (aro);
return ;
}
The solution is pretty simple. I've made a new program from start again (for sake of understanding). According to your requirement, you wants to get input of array elements from the user dynamically and assign them to a constructor and use a method to print the highest value.
Consider the following code:
#include <iostream>
using namespace std;
const int N = 100;
class Numbers
{
int largest = 0;
public:
Numbers(int, int[]);
void showHighest(void)
{
cout << largest << endl;
}
};
Numbers::Numbers(int size, int arr[])
{
for (int i = 0; i < size; i++)
{
if (arr[i] > largest)
{
largest = arr[i];
}
}
}
int main(void)
{
int arrays[N], total;
cout << "How many elements? (starts from zero) ";
cin >> total;
for (int i = 0; i < total; i++)
{
cout << "Element " << i << ": ";
cin >> arrays[i];
}
Numbers n(total, arrays);
n.showHighest();
return 0;
}
Output
How many elements? (starts from zero) 3
Element 0: 12
Element 1: 16
Element 2: 11
16
Note: I've initialized a constant number of maximum elements, you can modify it. No vectors, etc. required to achieve so. You can either use your own values by removing the total and its followed statements and use only int arrays[<num>] = {...} instead. You're done!
Enjoy coding!
I suggest to use std::vector<int> or std::array<int>.
If you want initialize with custom values you can do std::vector<int> m_vec {0, 1, 2};
Thank you so much for your help. I was basically confused about how to use arrays in a constructor and use setters/getters for arrays in a class. But you all helped a lot. Thanks again.
Numbers(int arr[])
{
for (int i=0;i<=9;i++)
{
Arr[i]=arr[i];
}
Largest=Arr[0];
Smallest=Arr[0];
}
void Largest_Number()
{
header_top("Largest Number");
Largest=Arr[0]; //Using this so we make largest value as index zero
for (int i=0 ; i<=9 ; i++)
{
if(Arr[i]>Largest)
{
setLargest( Arr[i] );
}
}
cout<<"Largest Number: "<<getLargest()<<endl;
}

How to call multiple classes in C++

Here is the code I'm trying to create, and yes its messy for now. To give some back story I'm trying to figure out how to call a class multiple times without doing it seperately. What I mean is instead of performing:
Dice diceOne;
Dice diceTwo; and so on, I want to know if it is possible to just put it as Dice dicewhatever(*) and have that be a modifiable variable. This is so that I can set that variable to a number and then decrement it based on a score.
I dont know if this is even possible, but at this point I've beat my head against this so much I'm just pulling at straws to see if it would be a fit.
class Dice {
public:
Dice();
int Roll();
int currentDiceSide();
private:
int diceRoll;
int diceReRoll; //Declares and initializes the number of dice to allow for roll next dice throw.
};
Dice::Dice()
: //This is the beginning of the class and sets diceRoll to zero
diceRoll(0)
{
}
int Dice::Roll()
{ //This function actually does the random roll within the class Dice.
diceRoll = ((rand() % 6) + 1);
return diceRoll;
}
int Dice::currentDiceSide()
{ //This function returns the value of the dice roll for the class call.
return diceRoll;
}
void Game::Rules()
{
ifstream inFile;
inFile.open("Farkle Rules.txt");
string line;
if (inFile.fail()) {
cerr << "Error opening file" << endl;
exit(1);
}
if (inFile.is_open()) {
while (inFile.good()) {
getline(inFile, line);
cout << line << endl;
}
inFile.close();
}
}
void Game::GetPlayerInput(int playerInput)
{
cin >> playerInput;
}
void Game::RunGame()
{
Rules();
bool farkle = false;
double turnSum = 0;
double value = 0;
int i = 0;
int w = 6;
int players = 0;
int numPlayer = 0;
int diceOneValue = 0;
int diceTwoValue = 0;
int diceThreeValue = 0;
int diceFourValue = 0;
int diceFiveValue = 0;
int diceSixValue = 0;
int num1s = 0; //Declaring and initializing the variables to hold how many times a number shows up in a roll.
int num2s = 0;
int num3s = 0;
int num4s = 0;
int num5s = 0;
int num6s = 0; //
srand(static_cast<unsigned int>(time(0)));
cout << "Welcome to Farkle!" << endl
<< endl;
cout << "Please enter the number of players " << endl;
cin >> players;
//Dice diceOne;
//diceOne.currentDiceSide();
//Dice diceTwo;
//diceTwo.currentDiceSide();
//Dice diceThree;
//diceThree.currentDiceSide();
//Dice diceFour;
//diceFour.currentDiceSide();
//Dice diceFive;
//diceFive.currentDiceSide();
//Dice diceSix;
//diceSix.currentDiceSide();
Dice diceOne(w);
< -this is the line that I would like to create with a variable that is modifiable.
You cannot give each Dice object a name, but you can create a Vector of Dice object pointers (vectors are basically resizable arrays), like this:
#include <vector>
#include <iostream>
//...
std::cout << "Please enter the number of players " << std::endl;
std::cin >> players;
// do something to make sure players is an integer
// initialize the empty playerDice vector
std::vector<Dice*> playerDice = {};
for (unsigned i = 0; i < players; ++i) {
playerDice.push_back(new Dice); // this adds a new Dice object pointer to the end of the vector
playerDice.at(i)->currentDiceSide();
}
You have then called the currentDiceSide() function on each Dice object you created, and have neatly organized them in a Vector, which you can access like this:
// say we want to access the third Dice Object,
// Vectors start counting at 0, so we acces the element at Index 2.
playerDice.at(2)->doSomething();
Now because you instantiated those Dice objects with new you have to remember to delete them when you're finished with them, otherwise this will create a memory leak.
//...
// this deletes all the Dice objects in the vector, and points the remaining pointers to null
for (auto d : playerDice) {
delete d;
d = nullptr;
}
Or, better yet, if you're using C++11, you can use std::unique_ptr instead of the raw C-style pointers. Those will prevent you from creating memory leaks, because they will be deleted when they go out of scope. Note you have to #include <memory> to use these.
The vector definition then turns into:
std::vector< std::unique_ptr<Dice> > playerDice = {};
And the creation of the objects would look like this
for (unsigned i = 0; i < players; ++i) {
Dice* temp = new Dice;
temp->currentDiceSide();
std::unique_ptr<Dice> uPtr{ temp };
playerDice.push_back(std::move(uPtr));
}
You can then just clear the vector when you're done with all the objects:
playerDice.clear();
which will delete all the Dice objects that you put into the vector.

C++ beginner declaring a function involving array of structures

There is a few lines of my code that I would like to define as a function because I plan to use it multiple times. portion of code is as follows:
// loop within loop used to reorder with highest price at the top
for(i=0;i<x;i++){
for(t=i;t<x;t++){
if(f[i].price < f[t].price) {
temp = f[i].price;
f[i].price = f[t].price;
f[t].price = temp;
}
}
}
I hope to be able to enter new values for x and f each time I call the function. I have included all of my code below. If I'm unclear about my objective in anyway please feel free to ask. I apologize in advance for the improper terminology I am new to this. Thank you
#include <iostream>
using namespace std;
struct List
{
char name[10];
int price;
};
int main()
{
//x represents number of structures within array!
int x;
cout << "How many items would you like to list under the fruit menu?\n";
cin >> x;
//array of structures fruit
struct List f[x];
int i;
//input values into structure
for (i = 0; i < x; i++) {
cout << "\nEnter fruit name, and price.\n";
cin >> f[i].name;
cin >> f[i].price;
};
//variables for reordering
int temp;
int t;
// loop within loop used to reorder with highest price at the top
for(i=0;i<x;i++){
for(t=i;t<x;t++){
if(f[i].price < f[t].price) {
temp = f[i].price;
f[i].price = f[t].price;
f[t].price = temp;
}
}
}
//Output of menus
//fruit Menu
cout << "\n\nFruit Menu";
for (i = 0; i < x; i++) {
cout << "\n" << f[i].name << " $" << f[i]. price;
};
return 0;
}
I suppose it is an assignment that says "implement your own sort function for sorting an array of fruits", so I take the data structure "array of fruits" as given. You can, of course, change this to vector<struct Fruit> as well, but that's a different topic.
Maybe the following fragments help you finishing your code. It contains functions for entering, sorting, and printing the array with some samples how to deal with the parameters and the calls. You'll have to finalise the code.
Have fun!
#include <iostream>
using namespace std;
struct Fruit
{
char name[10];
int price;
};
// enter up to nrOfFruis; return number of fruits actually entered
int enterFruits(struct Fruit *fruits, int maxNrOfFruits) {
int entered = 0;
while (entered < maxNrOfFruits) {
cin >> fruits[entered].name;
entered++;
}
return entered;
}
void sortFruits(struct Fruit* fruits, int nrOfFruits) {
// your sort code goes here
// example for swaping two elements:
Fruit temp = fruits[0];
fruits[0] = fruits[1];
fruits[1] = temp;
}
void printFruits(struct Fruit *fruits, int nrOfFruits) {
cout << "\n\nFruit Menu";
for (int i = 0; i < nrOfFruits; i++) {
cout << "\n" << fruits[i].name << " $" << fruits[i]. price;
};
}
int main()
{
// Your task: put a proper loop and exit condition arround the following lines...
int x;
cout << "How many items would you like to list under the fruit menu?\n";
cin >> x;
struct Fruit fruits[x];
int entered = enterFruits(fruits, x);
sortFruits(fruits, entered);
printFruits(fruits, entered);
return 0;
}
You cannot allocate an array on the stack if you do not know it's size at compile time. Therefore, you need to dynamically allocate memory for it(you also need to remember to delete it):
//x represents number of structures within array!
int x;
cout << "How many items would you like to list under the fruit menu?\n";
cin >> x;
//array of structures fruit
struct List * f = new List[x];
//...
delete [] f;
Alternatively, you could do it the C++ way, using vector, having the vector elements on the stack:
int x;
std::cin>>x;
std::vector<A> v(x);
for( size_t i = 0; i < x; i++)
{
std::cin >> v[i].x;
}
If you just want to pass an array to a function you can do so like this:
void sortArray(struct List list[]);
void sortArray(struct List* list, int n); // n = size of array
may be better to just use std::vector or some other list container instead. :)
Sounds like you want a function that receives an array t and index x, and you want to mutate the array in the function?
C++ is "pass by value", so to mutate the array you have to have your function take a reference (or pointer) to the array so that you're mutating the original array and not a copy of it, so just have your function signature like this: func(T& t, int x) (assuming T is the type of array t).

C++ Dynamic Array of Objects Sorting by Property

I'm trying to implement selection sort as a member function within class, to sort the objects of the class where the number of total players are being got by user input, also the names and scores of the players are being got by user too.
I'll sort the player objects by the property of their scores, which is a class member, being got by user input.
My problem is, i got stuck within the main where i can't call the class' member function sort for the array of objects.
class Player{
private:
string name;
int score;
public:
void setStatistics(string, int) // simple setter, not writing the whole function
void sortPrint(int, Player []);
int getScore(){ return score; }
void print(){ cout << name << " " << score << endl; }
};
void Player::sortPrint(int n, Player arr[]){
int i, j, minIndex;
Player tmp;
for (i = 0; i < n - 1; i++) {
int maxIndex = i;
for (j = i + 1; j < n; j++)
{
if (arr[j].getScore() > arr[minIndex].getScore())
{
minIndex = j;
}
}
if (minIndex != i) {
tmp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = tmp;
}
for(int i=0; i<n; i++){
arr[i].print(); // not sure with this too
}
}
};
int main(){
int n,score;
string name;
cout << "How many players ?" << endl;
cin >> n;
Player **players;
players = new Player*[n];
for(int i=0;i<n;i++) {
cout << "Player's name :" << endl;
cin >> name;
cout << "Player's total score:" << endl;
cin >> score;
players[i] = new Player;
players[i]->setStatistics(name,score);
}
for(int i=0; i<n;i++){
players->sortPrint(n, players); // error here, dont know how to do this part
}
// returning the memory here, didn't write this part too.
}
Try to replace void Player::sortPrint(int n, Player arr[]) with void Player::sortPrint(int n, Player*) and call function like players->sortPrint(n, *players)
Your problem is, that players is a pointer to array of Player, and arrays do not have member functions of the containees. As Player::sortPrint does not depend on the object itself, declare it as static and call it like Player::sortPrint(n, players);
Unless you have a very good reason not to, you should use std::sort rather than your own sorting algorithm. You should use a comparison function which compares the score of each player.
The following should work in C++03:
bool comparePlayerScores(const Player* a, const player* b)
{
return (a->getScore() < b->getScore());
}
// Returns the players sorted by score, in a new std::vector
std::vector<Player*> getSortedPlayers(Player **players, int num_players)
{
std::vector<Player*> players_copy(players, players + num_players);
std::sort(players_copy.begin(), players_copy.end(), comparePlayerScores);
return players_copy;
}
void printSorted(Player **players, int num_players)
{
std::vector<Player*> sorted_players = getSortedPlayers(players, num_players);
// Could use iterators here, omitting for brevity
for (int i = 0; i < num_players; i++) {
sorted_players[i]->print();
}
}
(Alternatively, you could define an operator< on your Player class which compares scores, which would let you store players in a std::set or std::map.)