how can one create a class with a constructor that counts the number of people who are alive,if i have 10 people it should count the quantity of people who are alive,people should be objects in this example,lets say i have a class man like this below
class man{
private:
string name;
man(string name=""){
cout<<"there 10 people alive"<<endl;
~man(){}
};
int main(){
}
i am getting confused on how to go about it,i really need a simple example i want to use the set and get methods
The sane version of this would be to store your man objects in a collection, say a std::vector. From this std::vector, you could use size on the vector to fetch the number of items contained in it.
Otherwise, go with a solution that doesn't make sense in this context, which would be to store a static variable that is increased in the constructor and decreased in the destructor.
By the way, your man class has a few mistakes, the constructor is private and you're missing brackets... here's a simple version of what you're looking for:
class man
{
private:
std::string mName;
public:
man(std::string name="") : mName(name)
{
}
const std::string& GetName() const
{
return mName;
}
};
int main(int argc, char *argv[])
{
man Bob = man("Bob");
man Jimmy = man("Jimmy");
std::vector<man> men; // This will copy the man object, might want to consider using pointers
men.push_back(Bob);
men.push_back(Jimmy);
std::cout << "There is " << men.size() << " men." << std::endl;
std::cout << "Known men are:" << std::endl;
for(std::vector<man>::const_iterator itor = men.begin(); itor != men.end(); ++itor)
{
std::cout << itor->GetName() << std::endl;
}
// You could also iterate using something like for(unsigned int i = 0; i < men.size(); ++i)
}
Edit:
Lets add how to handle it if you're going with a static variable... see the following scenario (I collapsed much of the brackets just to make it shorter)
See the following code:
class man
{
private:
static unsigned int sCount;
std::string mName;
public:
man(std::string name="") : mName(name) { ++sCount; }
~man() { --sCount; }
const std::string& GetName() const { return mName; }
static unsigned int Count() { return sCount; }
};
unsigned int man::sCount = 0;
int main(int argc, char *argv[])
{
man Bob = man("Bob");
man Jimmy = man("Jimmy");
std::cout << "There is " << man::Count() << " men" << std::endl;
std::vector<man> men; // This will copy the man object, might want to consider using pointers
men.push_back(Bob);
men.push_back(Jimmy);
std::cout << "There is " << man::Count() << " men" << std::endl;
}
The output to that will be
There is 2 men
There is 1 men
Wait... what?!? Where did we lose a man? Well, this happened in the vector resizing, since we didn't define a copy constructor, the compiler did it for us, but the compiler wasn't aware that we wanted to increment sCount, so when the vector resized, new objects were created, old ones destructed, and sCount didn't get updated properly.
By changing our man class to:
class man
{
private:
static unsigned int sCount;
std::string mName;
public:
man(std::string name="") : mName(name) { ++sCount; }
man(const man& in_man) : mName(in_man.mName) { ++sCount; }
~man() { --sCount; }
const std::string& GetName() const { return mName; }
static unsigned int Count() { return sCount; }
};
We now have:
There is 2 men
There is 4 men
But why?!?. There are 2 man objects on the stack, Bob and Jimmy. Then there's 2 copy of these these objects in std::vector<man> men because the vector contains "objects of type man".
If we changed this to pointers:
std::vector<man*> men;
men.push_back(&Bob);
men.push_back(&Jimmy);
We now have the following output, which is what we're looking for:
There is 2 men
There is 2 men
Hope this clears things up for you!
Use static class field to count people.
Such variables are shared between all objects of a given class, so increasing it in constructors and decreasing in destructors will count "people".
Related
I have an array of objects and I want to transfer the objects to another array. I've written the code bellow to do so but it did not work. It is basically a code where 52 card objects are created in one array and distributed between two arrays.Can anyone help me?
class card
{
public:
string suit;
string value;
void setValue(string v);
void setSuit(string s);
};
void card::setValue(string v)
{
value=v;
}
void card::setSuit(string s)
{
suit=s;
}
int main()
{
string suites[]={"Spades","Hearts","Diamonds","Clubs"};
string values[]={"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
card cards[52];
int i=0;
for(int j=0;j<4;j++){
for(int k=0;k<13;k++){
cards[i].setSuit(suites[j]);
cards[i].setValue(values[k]);
i++;
}
}
card player1_cards[26];
card player2_cards[26];
for(int a=0;a<52;a++){
if(a%2==0){
player1_cards[a]=cards[a];
}
else{
player2_cards[a]=cards[a];
}
}
return 0;
}
If you want every 2nd card to be added to player1_cards and the others to be added to player2_cards you can change your for-loop to:
for(int a=1;a<26;a++) {
player1_cards[a] = cards[2*a];
player2_cards[a] = cards[2*a-1];
}
As Eljay said in the comment to your question your index went past the end of the array.
I tried to compile the code myself and it seems like the following code splits the cards in to two different arrays, althought it is not random (which you might want to add if you are doing a card game).
#include <iostream>
#include <string>
class card
{
public:
std::string suit;
std::string value;
void setValue(std::string v);
void setSuit(std::string s);
std::string printSV();
};
void card::setValue(std::string v)
{
value=v;
}
void card::setSuit(std::string s)
{
suit=s;
}
std::string card::printSV() {
return suit + ": " + value + "\n";
}
int main()
{
std::string suites[]={"Spades","Hearts","Diamonds","Clubs"};
std::string values[]={"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
card cards[52];
int i=0;
for(int j=0;j<4;j++){
for(int k=0;k<13;k++){
cards[i].setSuit(suites[j]);
cards[i].setValue(values[k]);
i++;
}
}
card player1_cards[26];
card player2_cards[26];
for(int a=1;a<26;a++){
player1_cards[a] = cards[2*a];
player2_cards[a] = cards[2*a-1];
// prints the suite and value for each card in player1's and player2's hand.
std::cout << player1_cards[a].printSV();
std::cout << player2_cards[a].printSV();
}
return 0;
}
Outputs Suite: Value for each of the cards in cards[52].
As #Eljay notes, you are trying to access elements past the end of the arrays. If you were to use a debugger to step through your program, you would see this.
However, this is also a lesson for you to be careful of writing raw loops, with a lot of "magic-number" indices, and prefer using pre-existing patterns from the libraries (especially std::algorithm) when relevant. See this talk by Sean Parent about this general principle.
Specifically, you could have written your program as follows:
#include <range/v3/view.hpp>
#include <string>
#include <array>
#include <iostream>
struct card {
std::string suite;
std::string value;
};
std::ostream& operator<<(std::ostream& os, const card& c)
{
return os << c.value << " of " << c.suite;
}
int main()
{
using namespace ranges;
std::array suites {"Spades","Hearts","Diamonds","Clubs"};
std::array values {"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
auto cards =
views::cartesian_product(suites, values) |
views::transform([](const auto& suite_and_value) -> card {
return { std::get<0>(suite_and_value), std::get<1>(suite_and_value) };
});
auto num_players { 2 };
auto player1_cards =
cards | views::stride(num_players);
auto player2_cards =
cards | views::drop(1) | views::stride(num_players);
std::cout << "Player 1 got: " << player1_cards << '\n';
std::cout << "Player 2 got: " << player2_cards << '\n';
}
in which case you don't use any loops and any index variables. This uses Eric Niebler's ranges-v3 library. See also this quick reference to understand faster what's going on in this code if you're not familiar with the terms.
See this Live on GodBolt.
I'm writing a entry-level script to model disease propagation. I'm trying to write it such that I can run multiple trials and output the result each time. The script uses a Person class and a Population class, which consists of a vector of persons. Each trial returns the same result (when tested individually they return different results from the same input). I think I need to wipe my population object each trial, but I'm not quite sure how.
I think I need a destructor but I'm unsure of the syntax. Online resources have been too advanced for my skill level, or have given me error messages when I try to copy their syntax.
class Person {
private: // Person constructor
int status; bool infected;
public:
Person(){
status = 0; infected = false;
};
string status_string(){ // Outputs status of each person with a symbol as a string
};
void update_per(){ // Updates status of each person if they are sic
};
void infect(int n){ // Infects person if they are susceptible (not recovered or vaccinated)
};
void vaccinate(){ // Changes status of person to being vaccinated
};
bool is_stable(){ // Determines if person has recovered from infection
};
int get_status() { // Returns status of person
};
};
class Population { //Create population class
private: //declare private variable npeople
int npeople;
vector<Person> population; //create a vector of Persons named population with size npeople
public:
Population(int n){
srand(time(NULL));
npeople = n;
population = vector<Person>(n);
};
~Population() //DESTRUCTOR
{
delete[] population;
};
void random_infection(int days){ //method to randomly infect one person
};
int count_infected() { //method to count the number of people infected
};
void update_pop(int ncontacts, float contagion, int days) { // Updates the status of each person in population, also simulates spread of disease through contact
};
void print_status(){ // Output status of each person in population
};
void vacc_pop(float prob){ // Vaccinates a set number of people in the population
};
};
int main() {
ofstream popsizeresults;
int size; // Asks user for size of population
int numtrials; // Asks user for number of trials
for (int jjjj=1; jjjj<=numtrials; jjjj++){
int maxsick = 0;
int day = 0;
Population population(size); // Create population
population.vacc_pop(0.5); // Vaccinate population
population.random_infection(5); // Infect one random person in population
int step = 1;
for ( ; ; step++){
// Output status of each person in population
cout<<"In step "<<step<< " #sick: "<<population.count_infected()<<" : ";
population.print_status();
cout<<endl;
// If no people are sick, then the disease has run its course
if(population.count_infected() == 0)
break;
// Update the status of each person and simulate spread of disease
population.update_pop(size*0.25,0.9,5);
if (population.count_infected() > maxsick){
maxsick = population.count_infected();
day = step;
}
}
popsizeresults.open("disease10.txt", ios::app);
popsizeresults << jjjj << "," << step << "," << maxsick << "," << day << "\n";
popsizeresults.close();
//population.~Population(); //call destructor
return 0;
}
}
Before I added the destructor (that isn't working), the output on disease10.txt produces a different for each trial but the same results for each. When it's tested one trial at a time (for the same inputs), it produces different results (which is the goal). I'm not sure if a destructor is actually the answer here, I'm very new to C++. Either way, I'm unsure how to replicate the different results for each trial.
Now I see what you're after, here's a very cut down demonstration of population reset.
See numbered notes in comments for improvements in style etc.
#include <vector>
#include <iostream>
// a very basic Person for exposition
class Person
{
public:
Person() { };
};
// Population cut down to the bare minimum
class Population
{
private:
// note 1: no need to store npeople. a vector has a size(). Why store the same thing twice
// note 2: never use `using namespace std;` at global scope. Spell out std:: explicitly
std::vector<Person> population;
public:
// note 3: number of people can never be negative, so why give ourselves the choice? make it unsiged
Population(unsigned n)
// note 4: use list initialisation in constructors
: population(n)
{
};
// note 5: no need for destructors. google "rule of none", "rule of 5", "rule of 3". Prefer rule of none
// answer:
// a specific function to reset the population
void reset(unsigned n)
{
// destroy old people
population.clear();
// make new people
population.resize(n);
}
// note 6: allows us to print a representation of a population for exposition
friend std::ostream& operator<<(std::ostream& os, Population const& pop)
{
for (Person const& p : pop.population)
{
os << '.';
}
os << "(" << pop.population.size() << " people)";
return os;
}
};
int main()
{
Population population = Population(10);
std::cout << population << '\n';
// note 6: reset the population
population.reset(5);
std::cout << population << '\n';
}
Expected output:
..........(10 people)
.....(5 people)
Live demo:
https://coliru.stacked-crooked.com/a/02868f61f6a3da4d
My problem is that I have many variables in my class and I want them to be accessed via an accessor method. Of course I could have several accessor functions to output my private variables but how can I make it so I can access any of them via an argument. My class:
class Character {
public:
void setAttr(string Sname,int Shealth,int SattackLevel,int SdefenseLevel) {
name = Sname;
health = Shealth;
attackLevel = SattackLevel;
defenseLevel = SdefenseLevel;
}
int outputInt(string whatToOutput) {
return whatToOutput //I want this to either be health, attackLevel or defenseLevel
}
private:
string name;
int health;
int attackLevel;
int defenseLevel;
};
Basically what I want to know is how do I return a private variable in regards to the outputInt function. Most OOP tutorials have one function to return each variable which seems like a very unhealthy thing to do in a large program.
C++ doesn't support what you try to accomplish: reflection or detailed runtime information about objects. There is something called "Run-Time Type Information" in C++, but it can't provide information about your variable name: the reason is because, in the compiled and linked binary this information (names of your variables) will not be necessarily present anymore.
However, you can accomplish something close to that, using i.e. std::unordered_map instead of plain integer variables. So it's possible to access values by their names, as strings.
Please consider the following code:
#include <string>
#include <iostream>
#include <unordered_map>
using namespace std;
class Character {
public:
void setAttr(const string& Sname, int Shealth, int SattackLevel, int SdefenseLevel) {
name = Sname;
values.insert(std::make_pair("health", Shealth));
values.insert(std::make_pair("attackLevel", SattackLevel));
values.insert(std::make_pair("defenseLevel", SdefenseLevel));
}
int outputInt(const string& whatToOutput) {
return values.at(whatToOutput);
}
private:
string name;
std::unordered_map<std::string, int> values;
};
int main(int argc, char* argv[]) {
Character yourCharacter;
yourCharacter.setAttr("yourName", 10, 100, 1000);
std::cout << "Health: " << yourCharacter.outputInt("health") <<std::endl;
std::cout << "Attack level: " << yourCharacter.outputInt("attackLevel") << std::endl;
std::cout << "Defense level: " << yourCharacter.outputInt("defenseLevel") << std::endl;
return 0;
}
It will output as expected:
Health: 10
Attack level: 100
Defense level: 1000
Another option without dependency on unordered_map would be, to use predefined static strings for your variable names and an array or vector for your values. So we could replace the class Character above with something like:
static std::string variableNames[3] = {
"health",
"attackLevel",
"defenseLevel"
};
class Character {
public:
void setAttr(const string& Sname, int Shealth, int SattackLevel, int SdefenseLevel) {
name = Sname;
variableValues[0] = Shealth;
variableValues[1] = SattackLevel;
variableValues[2] = SdefenseLevel;
}
int outputInt(const string& whatToOutput) {
int retVal = 0;
for (size_t i = 0; i < sizeof(variableNames)/sizeof(std::string); ++i) {
if (!whatToOutput.compare(variableNames[i])) {
retVal = variableValues[i];
}
}
return retVal;
}
private:
string name;
int variableValues[3];
};
And getting still same output. However, here you have to manage a list with all your variable names inside the string array manually - I don't like this solution and would prefer one of the others above personally.
Most common ways in C++ to handle such a design is to have seperate getHealth(), getAttackLevel(), getDefenseLevel() functions instead. However, this will miss one use-case, which is: if you want to let the user input a string, like i.e. "health" and display the corresponding variable then, you would need to write code by yourself to call the corresponding getXXX() function. If this is not a issue in your case, consider the following code which is much cleaner:
#include <string>
#include <iostream>
using namespace std;
class Character {
public:
void setAttr(const string& Sname, int Shealth, int SattackLevel, int SdefenseLevel) {
name = Sname;
health = Shealth;
attackLevel = SattackLevel;
defenseLevel = SdefenseLevel;
}
int getHealth() const { return health; }
int getAttackLevel() const { return attackLevel; }
int getDefenseLevel() const { return defenseLevel; }
private:
string name;
int health, attackLevel, defenseLevel;
};
int main(int argc, char* argv[]) {
Character yourCharacter;
yourCharacter.setAttr("yourName", 10, 100, 1000);
std::cout << "Health: " << yourCharacter.getHealth() <<std::endl;
std::cout << "Attack level: " << yourCharacter.getAttackLevel() << std::endl;
std::cout << "Defense level: " << yourCharacter.getDefenseLevel() << std::endl;
return 0;
}
One other unrelated advice: Instead of using string as parameter types for your functions, use const string& (const reference to string; see my example code above). This allows easier calling of your functions (they can be called directly with an string literal without the need to create additional variables in the calling code) and they will not make a additional unnecessary copy. The only copy then will take place at: name = Sname; (in your code two copies took place).
I don't know if it can be a good idea for you, but you can use a public typedef struct that you pass by reference and set your value.
class Character {
public:
//...
typedef struct allvalues{
string vname;
int vhealth;
int vattackLevel;
int vdefenseLevel;
}allvalues;
void getValues(allvalues& val){
val.vname = name;
val.vhealth = health;
val.vattackLevel = attackLevel;
val.vdefenseLevel = detenseLevel;
}
//...
};
//...
//somewhere in the code
Character myCarac;
//...
//Here how to use it
Character::allvalues values;
myCarac.getValues(values);
I'm a beginner in C++ and I understand basic concepts of "pass-by-value or reference", object scope and object instantiation with and without use of the keyword "new" in simple examples. The problem is that when the problems that I'm trying to solve become more complicated, I don't know how is this theory I know from simple examples applied in problems that consists of multiple classes.
I have a PaintWidget.cpp which is responsible for painting all the Vehicles.
void PaintWidget::paintEvent(QPaintEvent *) {
if (!Vehicle::GetVehicles()->empty()) {
cout << "not null" << endl;
QPainter painter(this);
QPen pen1(Qt::red);
pen1.setWidth(2);
std::vector<Vehicle>::iterator it;
for (it = Vehicle::GetVehicles()->begin(); it != Vehicle::GetVehicles()->end(); it++) {
cout << "draaaaw" << endl;
QRect rect(it->GetXcord(), it->GetYcord(), it->GetWidth(), it->GetHeight());
cout << std::to_string(it->GetXcord()) + " " + std::to_string(it->GetYcord()) + " " + std::to_string(it->GetWidth()) + " " + std::to_string(it->GetHeight()) + " " << endl;
painter.setPen(pen1);
painter.drawRect(rect);
}
} else {
cout << "is null" << endl;
}
}
And then I have Vehicle.h
#ifndef VEHICLE_H
#define VEHICLE_H
#include <vector>
#include <map>
class Vehicle {
public:
Vehicle();
Vehicle(const Vehicle& orig);
virtual ~Vehicle();
void initVehicles();
Vehicle createVehicle();
static std::map<Road, int> &GetVeh_num() {
return veh_num;
}
static std::vector<Vehicle> *GetVehicles() {
return &vehicles;
}
private:
int xcord;
int ycord;
int height = 20;
int width = 50;
static std::vector<Vehicle> vehicles;
static std::map<Road, int> veh_num;
};
#endif /* VEHICLE_H */
Vehicle.cpp
#include "Vehicle.h"
#include <vector>
std::vector<Vehicle> Vehicle::vehicles;
std::map<Vehicle::Road, int> Vehicle::veh_num = {
{Vehicle::Top, 0},
{Vehicle::Right, 0},
{Vehicle::Bottom, 0},
{Vehicle::Left, 0}
};
Vehicle::Vehicle() {
}
Vehicle::Vehicle(const Vehicle& orig) {
}
Vehicle::~Vehicle() {
}
int Vehicle::GetXcord() const {
return xcord;
}
int Vehicle::GetYcord() const {
return ycord;
}
void Vehicle::SetXcord(int xcord) {
this->xcord = xcord;
}
void Vehicle::SetYcord(int ycord) {
this->ycord = ycord;
}
int Vehicle::GetHeight() const {
return height;
}
int Vehicle::GetWidth() const {
return width;
}
void Vehicle::initVehicles() {
for (int i = 0; i < 5; i++) {
Vehicle::vehicles.push_back(this->createVehicle());
}
}
Vehicle Vehicle::createVehicle() {
std::map<Vehicle::Road, int>::iterator it;
Vehicle v;
for (it = Vehicle::veh_num.begin(); it != Vehicle::veh_num.end(); it++) {
int &vehnum = it->second;
if (it->first == Vehicle::Road::Right) {
int xc = 520 + vehnum * this->GetWidth() + vehnum * 5;
int yc = 220;
v.SetXcord(xc);
v.SetYcord(yc);
v.SetRoad(Vehicle::Right);
}
}
return v;
}
As you can see, createVehicle returns copy of a new Vehicle which is then inserted in the static variable Vehicles. GetVehicles returns pointer to vector of inserted vehicles because I don't want to return a copy. When I run this code, nothing gets painted although there are 5 objects in the static variable (paintEvent gets called and string "draaaaw" is printed 5 times). I suspected that I have a problem with object life span, so I changed
static std::vector<Vehicle> vehicles;
to
static std::vector<Vehicle*> vehicles;
and of course instantiation of Vehicle from
Vehicle v;
to
Vehicle *v = new Vehicle();
which creates an object on the heap if I understand correctly. After all required changes in methods, my code works (all objects are painted). What I don't understand is when these objects get destroyed and why, if I'm returning a copy every single time. How come vector vehicles is not empty (I still have 5 "ghost" objects that do not contain any values I set earlier). As far as I understand creating objects with new is not recommended, so the second option are smart pointers?
Thanks :)
Edit
I purposely left out setters and getters in .h and .cpp file so that the code is as short as possible with only relevant information.
I think your main problem is you have defined an empty copy constructor:
Vehicle::Vehicle(const Vehicle& orig)
{
}
This means that when you add a Vehicle to a container, a copy is made that doesn't actually copy anything. You should delete your own constructor and let the compiler do the work for you.
You will never have a problem with object life span if you don't use pointers or references. It simply isn't possible for that to occur. The whole concept of "RAII" is that if the variable is accessible in code, it is valid.
To test this, also print out the coordinates and size of your vehicle. If that prints a valid result, you know that your issue lies in the paint function itself.
So just don't pass a pointer of the object unless you need to modify it, and even then return a reference instead of a pointer. Just make sure not to return a reference of a temporary, as that CAN lead to life span issues.
I have few maps in my project, which I don't know, how to use or simple said: I don't know how to cout some info from map, which has class attached.
My code (item.h):
#ifndef ITEM_H
#define ITEM_H
class Item
{
public:
int level, durability, damage, armor, weight, grade, sex;
Item(int _level, int _durability, int _damage, int _armor, int _weight, int _grade, int _sex);
Item();
virtual ~Item();
protected:
private:
};
#endif // ITEM_H
code (item.cpp):
#include "include/Item.h"
Item::Item(int _level, int _durability, int _damage, int _armor, int _weight, int _grade, int _sex)
{
level = _level;
durability = _durability;
damage = _damage;
armor = _armor;
weight = _weight;
grade = _grade;
sex = _sex;
}
Item::Item(): level(0), durability(20), damage(0), armor(0), weight(1), grade(1), sex(0)
{
//dtor
}
Item::~Item()
{
//dtor
}
Code (main.cpp):
std::map<std::string, Item> item;
// level, durability, damage, armor, weight, grade, sex
item.insert(std::pair<std::string, Item>("Wooden Sword", Item(1, 19, 3, 0, 1, 1, 0)));
How to cout some info from the selected array from map? Tried searching in the google, etc. Can't find answer and explanation why do I get error if I try something like this:
cout << item["Wooden Sword"]["level"];
for what purpose you can use item.find("Wooden Sword"); ?
how does map work with classes? How can I select data from maps which have classes. Really thanks in advance. :) Hope I explained what I want and gave you everything that you need.
The index operator returns a reference to the data element, in your case it returns an Item& that you use as a normal structure:
std::cout << item["Wooden Sword"].level << '\n';
As for the find function it returns an iterator. If you don't know about iterators, study them first.
If you want a good reference, see e.g. this site.
Using item.find("Wooden Sword"); you get an iterator to the matching key/value pair element. If there is no key like "Wooden Sword" it returns end(item);. Use find if you don't know if the item exists and don't want to add one.
auto it = item.find("Wooden Sword");
if (it != end(item))
{
std::cout << it->level; // use the -> operator
// std::string key = it.first;
// Item& item = it.second;
}
else
std::cout << "There is no Wooden Sword";
The []operator returns a reference to the matching item. If there is no item associated with this key, a new item will be inserted at this position.
std::cout << item["Wooden Sword"].level;