Cannot modify the private value in member function of the class - c++

I am wondering what is going on in my app.
The problem is that I cannot modify one of my private values (temperature) from the class Room while the other private one (targetTemp) changes without any problems.
I've got a function setTargetTemp where I can assign the value for targetTemp - works (Room.cpp line 18-20).
I've got another function outsideImpact where I can assign the value for temperature - doesn't work (Room.cpp line 21-27). The method is the same (excluding some calculations).
In main.cpp I called both functions (line 15 and 16) in a loop. While debugging I can see that livingRoom's temperature remains the same at every iteration, targetTemp on the other hand is changing as expected.
So what is the difference? What am I missing here?
Room.h
class Room {
private:
float
temperature, // Temperature in the room
targetTemp, // Target temperature in the room
factor; // Susceptibility of the room to cooling/heating - 1 is default, +- 0.25 = ~ 1.5 C-deg / >1 - faster
public:
Room(void);
~Room(void);
float getTemp(void);
float getTargetTemp(void);
void setTargetTemp(float target);
void outsideImpact(float outsideTemp);
};
Room.cpp
#include "./Room.h"
#include <iostream>
#include <cmath>
Room::Room(void) {
temperature = 15.;
targetTemp = 22.;
factor = 1;
}
Room::~Room(void) {}
float Room::getTemp(void) {
return temperature;
}
float Room::getTargetTemp(void) {
return targetTemp;
}
void Room::setTargetTemp(float target) {
targetTemp = target;
}
void Room::outsideImpact(float outsideTemp) {
float trendValue = (abs(temperature - outsideTemp) / 100 * factor);
if(temperature > outsideTemp)
temperature -= trendValue;
else
temperature += trendValue;
}
main.cpp
#include "./Room.h"
#include <iostream>
#include <cmath>
using namespace std;
int main(void){
float
timer = 0.,
outsideTemp = -10.;
Room livingRoom;
do {
timer += 0.25;
livingRoom.outsideImpact(outsideTemp); // change the "temperature"
livingRoom.setTargetTemp(26.+timer); // change the "targetTemp"
cout << "Living room temp: " << livingRoom.getTemp() << " || Outside temp: " << outsideTemp
<< " || Time: " << timer << " hour(s)" << "\t|| TARGET: " << livingRoom.getTargetTemp() << endl;
} while (round(livingRoom.getTemp()) != round(outsideTemp));
return 0;
}

Related

CPP: why is dereferencing a pointer to a template type not populating a variable?

I do a lot of modeling and simulation and I am writing a sim_logger in CPP. The basics of it are this: a user constructs the class with a logging frequency and an output path. They can then "register" any number of variables which gives the logger a reference to the desired variable (its not incredibly safe right now but I'll work on that later, focused on the issue at hand). I've created a template type called "variable" which contains three things, T *var, T last_val, and string ID. My problem is this, whenever I set the last_val equivalent to the var, the last_val inside the variable does not actually change. I am setting this value in line 180 of sim_logger.h. I feel like this is a silly problem, probably due to some misunderstanding I have of pointers. However, I've tried several different things and cannot seem to solve this problem.
sim_logger.h
#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>
#include <variant>
#include <type_traits>
#include <math.h>
pragma once
// a class to log simulation data
// specifically for logging time dependent differential functions
class sim_logger
{
private:
// a type that represents a variable
/*
meant to contain anything, but limited by the variadic type
"poly_var_types" below
*/
template <typename T>
struct variable
{
T *var; // pointer to the variable itself
T last_val; // the last value of the variable
std::string ident; // the identity of the variable
};
// a variadic type
template <typename ... T>
using poly_var_types = std::variant<T...>;
// defined variable types
// these are the typical types that are logged, feel free to add more
using var_types = poly_var_types<
variable<double>,
variable<float>
// variable<int>,
// variable<bool>,
// variable<std::string>
>;
// class members
std::vector<var_types> registered_variables; // container of all variables
std::ofstream file; // output file stream
double dt; // the logging time step in seconds
double clock = 0.0; // the logging clock in seconds
double last_sim_time = clock; // the last sim time for interp
bool is_time_to_log = false; // flag for log function
const double EPSILON = 0.000000001; // rounding error
// a linear interpolation method
// only returns floating point values
double lin_interp(double x, double x1, double x2, double y1, double y2)
{
return (y1+(x-x1)*((y2-y1)/(x2-x1)));
}
public:
// constructor which sets the logging frequency and output path
// log_dt is a floating point value in units of seconds
// path_to_file is a string representation of the desired output path
sim_logger(double log_dt, std::string path_to_file)
{
dt = log_dt;
file.open(path_to_file);
file << std::setprecision(16) << std::fixed;
}
// method to register a variable with the logger
template <typename T>
void register_variable(std::string ident, T *aVar)
{
variable<T> v;
v.ident = ident;
v.var = aVar;
registered_variables.push_back(v);
};
// a method to write the log file header and log sim time 0.0 data
void write_header_and_log_init_data()
{
// write header
file << "sim_time" << " ";
for (int i = 0; i < registered_variables.size(); i++)
{
std::visit([&](auto rv)
{
if (i == registered_variables.size()-1)
file << rv.ident << "\n";
else
file << rv.ident << " ";
}, registered_variables[i]);
}
// log all registered variables
file << clock << " ";
for (int i = 0; i < registered_variables.size(); i++)
{
std::visit([&](auto rv)
{
if (i == registered_variables.size()-1)
file << *rv.var << "\n";
else
file << *rv.var << " ";
}, registered_variables[i]);
}
}
// method to log all registered variables
void log_data(double sim_time)
{
// check the timing
if (sim_time > (clock + dt))
{
is_time_to_log = true;
}
// check if its time to log
if (is_time_to_log)
{
// update the clock
clock += dt;
// debug
std::cout << "\n";
// log all registered variables
file << clock << " ";
for (int i = 0; i < registered_variables.size(); i++)
{
std::visit([&](auto rv)
{
// instantiate the value to be logged
double log_val;
// debug
std::cout << rv.last_val << " " << *rv.var << std::endl;
// if sim time is even with clock time, log at time
if (fabs(sim_time - clock) < EPSILON)
// if (true)
{
log_val = *rv.var;
}
// if sim time is past clock time, interpolate
else
{
log_val = lin_interp(sim_time, last_sim_time,
clock, rv.last_val, *rv.var);
}
// if last variable in vector create new line
if (i == registered_variables.size()-1)
file << log_val << "\n";
// otherwise just whitespace
else
file << log_val << " ";
}, registered_variables[i]);
}
// debug
std::cout << "\n";
// reset flag
is_time_to_log = false;
}
// get all the last values
for (int i = 0; i < registered_variables.size(); i++)
{
std::visit([&](auto rv)
{
// have to get last value at every update call
// This works in scope but the memory does not actually change?
// I am very confuse.
rv.last_val = *rv.var;
// debug
std::cout << rv.last_val << " " << *rv.var << std::endl;
}, registered_variables[i]);
}
// set the last sim time
last_sim_time = sim_time;
}
};
main.cpp
include <iostream>
include "sim_logger.h"
int main()
{
sim_logger logger(0.1, "sim_logger/log.dat");
double test1 = 100.0;
double test2 = 100.0;
double test3 = 100.0;
logger.register_variable("test1", &test1);
logger.register_variable("test2", &test2);
logger.register_variable("test3", &test3);
logger.write_header_and_log_init_data();
double simTime = 0.0;
double simDt = 1.0 / 20.0;
for (int i = 0; i < 3; i++)
{
simTime += simDt;
test1 += 1.0;
test2 += 2.0;
test3 += 3.0;
logger.log_data(simTime);
}
return 0;
};
output
101 101
102 102
103 103
102 102
104 104
106 106
1.88705e-26 103
1.88705e-26 106
1.88705e-26 109
103 103
106 106
109 109
std::visit([&](auto rv)
rv is, effectively, a parameter to this function (the closure, for the purposes of this answer, is effectively a function).
As you know: in C++ function parameters get passed by value. For example, using a simple function:
void func(int x)
{
x=5;
}
This func can set x to 5 as often as it wants. Whatever actually gets passed in, by anyone that calls func(), will remain unaffected:
int z=7;
func(z);
z is still 7. Even though func set its parameter to 5. This is fundamental to C++:
std::visit([&](auto rv)
{
rv.last_val = *rv.var;
So, this sets rv.last_val. Great. But this has no effect on whatever gets passed into here.
}, registered_variables[i]);
The visited instance of this variant is still what it is. It hasn't changed. Why would it change? C++ does not work this way.
So, if your intent, here, is to modify registered_variables[i], it should be passed by reference:
std::visit([&](auto &rv)
Now, the object referenced by rv gets modified.

A queue in my producer-consumer app is indicated as empty, after the queue is added to. How do I fix this?

My program is split up into two types of threads: producer, and consumer. The "producer" threads model the production of cars, while the "consumer" threads model the selling of the cars. The idea is for a consumer thread to sell a car as soon as the car is produced, so I'm using a binary semaphore for the consumer thread(s) to wait for a car to be produced, as signalled by each "producer" thread.
Here is my code:
cars.h
/***********************************************************************
* Component
* Cars
* Summary:
* This will deal with the details of working with cars
*
* Note that you must compile this with the -lpthread switch:
* g++ -lpthread lab06.cpp
************************************************************************/
#ifndef CARS_H
#define CARS_H
#include <iostream> // for COUT
#include <queue> // for QUEUE
#include <cassert> // for ASSERT
/*************************************************
* CAR
* A car in the inventory consists of a model and a serial number
************************************************/
struct Car
{
const char * model;
int serialNumber;
};
/******************************************
* DISPLAY CAR
* Display one car in a user-friendly way
****************************************/
inline std::ostream & operator << (std::ostream & out, const Car & car)
{
out << car.model << "(#" << car.serialNumber << ")";
return out;
}
// the number of cars in the production run across all models
#define NUM_CARS 50
// The major models are the following
const char * models[4] =
{
"540",
"570GT",
"650S Spider",
"P1"
};
inline int numModels() { return sizeof(models) / sizeof(models[0]); }
// A sampling of the retailers are the following
const char * retailers[9] =
{
"McLaren Beverly Hills",
"McLaren Monaco",
"McLaren Palm Beach",
"McLaren Philadelphia",
"McLaren Atlanta",
"McLaren Rancho Mirage",
"McLaren Tampa Bay",
"McLaren Paris",
"McLaren Birmingham"
};
inline int numRetailers() { return sizeof(retailers) / sizeof(retailers[0]); }
/*************************************************************
* INVENTORY
* The cars currently in inventory.
* This class is _NOT_ thread-safe and should not be made so
************************************************************/
class Inventory
{
public:
// default constructor: no cars
Inventory() : maxCars(0) {}
// how many cars were in there?
int getMax() const { return maxCars; }
// is the inventory empty?
bool empty() const { return cars.size() == 0 ? true : false; }
// add a car
void makeCar(const Car & car)
{
cars.push(car);
maxCars = (cars.size() > maxCars ? cars.size() : maxCars);
}
// sell a car
Car sellCar()
{
assert(cars.size() > 0);
Car car = cars.front();
cars.pop();
return car;
}
private:
int maxCars; // the biggest the inventory has yet been
std::queue <Car> cars; // the actual cars in the inventory
};
#endif // CARS_H
The lab
#include <iostream> // for COUT
#include <cassert> // for ASSERT
#include <string> // for STRING
#include <sstream> // for STRINGSTREAM
#include <queue> // for QUEUE
#include <ctime> // for time(), part of the random process
#include <unistd.h> // for usleep()
#include <stdlib.h> // for rand() and srand()
#include "cars.h" // for everything dealing with McLaren Cars
#include <semaphore.h>
using namespace std;
// Mutex locks
pthread_mutex_t serialNumberLock;
pthread_mutex_t inventoryLock;
// Semaphore
sem_t semaphore;
// This variable represents the shared memory between the parent thread
// and all the children. Recall from the reading how the main way for
// threads to communicate is through shared memory. This shared memory
// needs to be global.
bool productionComplete = false;
/***********************************************
* PRoDUCER_ARGS
* This stores arguments for the "producer" function.
***********************************************/
struct ProducerArgs
{
const char *model;
int producerNumber=0;
Inventory *inventory;
int beginningSerialNumber=0;
int endingSerialNumber=0;
};
/***********************************************
* CONSUMER_ARGS
* This stores arguments for the "consumer" function.
***********************************************/
struct ConsumerArgs
{
const char* retailer;
Inventory *inventory;
};
void * producer(void *args); // you may need to change this
void * consumer(void *args); // you may need to change this also
int getNumber(const char * prompt, int max);
/***********************************************
* MAIN
* This will serve to prompt the user for the number
* of models and the number of retailers. It will then
* begin the simulation
***********************************************/
int main(int argc, char **argv)
{
// Initialize the semaphore.
sem_init(&semaphore,0,1);
// set up the random number generator
srand(argc == 1 ? time(NULL) : (int)argv[1][1]);
// determine how many producer and consumer threads
int numProducer = getNumber("How many models? ", numModels());
int numConsumer = getNumber("How many retailers? ", numRetailers());
// produce the cars. Note that this code needs to change. We will
// need to launch one thread per producer here
// Consumer threads should fire as soon as a producer produces a car.
Inventory inventory;
pthread_t *producerThreads = new pthread_t[numProducer];
// Divide the work among the threads.
int numCars[4];
int numCarsPerProducer = NUM_CARS / numProducer;
int remainderCarsPerProducer = NUM_CARS % numProducer;
for (int i=0; i < numProducer; i++)
numCars[i] = numCarsPerProducer;
if (remainderCarsPerProducer > 0)
numCars[0] += remainderCarsPerProducer;
int beginningSerialNumber=1;
int endingSerialNumber=0;
ProducerArgs *producerArgs = new ProducerArgs[numProducer];
for (int i = 0; i < numProducer; i++)
{
ProducerArgs *pArgs = &(producerArgs[i]);
pArgs->model = models[i];
pArgs->inventory = &inventory;
pArgs->producerNumber = i;
pArgs->beginningSerialNumber = beginningSerialNumber;
endingSerialNumber += numCars[i];
pArgs->endingSerialNumber = endingSerialNumber;
assert(pArgs->endingSerialNumber <= numProducer * NUM_CARS);
assert(pthread_create(
&(producerThreads[i]),
NULL,
producer,
pArgs
) == 0);
beginningSerialNumber = endingSerialNumber + 1;
}
assert(endingSerialNumber == 50);
// sell the cars. Note that this code also needs to change.
cout << "\nThe cars sold from the various retailers:\n\n";
ConsumerArgs *consumerArgs = new ConsumerArgs[numConsumer];
pthread_t *consumerThreads = new pthread_t[numConsumer];
for (int i = 0; i < numConsumer; i++)
{
ConsumerArgs *args = &(consumerArgs[i]);
args->retailer = retailers[i];
args->inventory = &inventory;
assert(pthread_create(
&(consumerThreads[i]),
NULL,
consumer,
args
) == 0);
};
for (int i=0; i < numConsumer; i++)
{
void *retVal;
pthread_join(consumerThreads[i],&retVal);
string report = *(string *)retVal;
cout << report << endl;
};
// final report
cout << "Maximum size of the inventory: "
<< inventory.getMax()
<< endl;
// Remove arrays from heap.
delete producerArgs;
delete producerThreads;
delete consumerArgs;
delete consumerThreads;
return 0;
}
/***********************************************************
* PRODUCER
* Create those cars.
* This function is not currently thread safe. You will need
* to introduce a critical section in such a way that we do
* not compromise the queue nor produce two cars with the
* same serial number.
**********************************************************/
void *producer(void *args)
{
ProducerArgs *producerArgs = (ProducerArgs *)args;
int producerNumber = producerArgs->producerNumber;
cout << "Producing car " << producerNumber << endl;
const char *model = producerArgs->model;
Inventory *inventory = producerArgs->inventory;
static int serialNumberNext = producerArgs->beginningSerialNumber;
// continue as long as we still need to produce cars in this run
while (serialNumberNext <= producerArgs->endingSerialNumber)
{
// now that we decided to build a car, it takes some time
usleep(rand() % 150000);
// a car to be added to the inventory
Car car;
car.model = model;
car.serialNumber = serialNumberNext;
// add the car to our inventory if we still need to
pthread_mutex_lock(&inventoryLock);
inventory->makeCar(car);
pthread_mutex_unlock(&inventoryLock);
serialNumberNext++;
}
// all done!
productionComplete = true;
assert(!inventory->empty());
// Signal to the consumer threads that production of a car is complete.
sem_post(&semaphore);
pthread_exit(NULL);
}
/***********************************************************
* CONSUMER
* Sell those cars.
* This function is not currently thread safe. You will need
* to introduce a critical section in such a way that we
* do not compromise the queue nor sell the same car twice.
**********************************************************/
void *consumer(void *args)
{
sem_wait(&semaphore);
bool inventoryEmpty;
ConsumerArgs *consumerArgs = (ConsumerArgs *)args;
const char *retailer = consumerArgs->retailer;
Inventory *inventory = consumerArgs->inventory;
// collect our sales history into one string
stringstream sout;
sout << retailer << ":\n";
// continue while there are still customers floating around
// do we have one to sell
pthread_mutex_lock(&inventoryLock);
inventoryEmpty = inventory->empty();
pthread_mutex_unlock(&inventoryLock);
assert(!inventoryEmpty);
// it takes time to sell our car
usleep(rand() % 150000);
cout << "Selling car. " << endl;
Car car = inventory->sellCar();
assert ((car.model != NULL) && (car.model != ""));
sout << car << endl;
// done
string * report = new string(sout.str());
return (void *)report;
}
/*********************************************
* GET NUMBER
* Generic prompt function with error checking
********************************************/
int getNumber(const char * prompt, int max)
{
int value = -1;
assert(cin.good()); // better not already be in error mode
assert(prompt != NULL); // the prompt better be a valid c-string
assert(max > 0); // it better be possible for valid data to exist
// continue prompting until we have valid data
while (value <= 0 || value > max)
{
cout << prompt;
cin >> value;
// if the user typed a non-integer value, reprompt.
if (cin.fail())
{
cin.clear();
cin.ignore();
cout << "Error: non-integer value specified\n";
}
// if the user typed a valid outside the range, reprompt
else if (value <= 0 || value > max)
cout << "Error: value must be between 1 and "
<< max
<< endl;
}
return value;
}

Trying to pass class as parameter to a different class constructor, but am getting "conversion" error

So I'm trying to pass a class as a parameter to another class (in a different header) and keep getting an error which I can't seem to debug.
Error:
'wanderingSoul::wanderingSoul(wanderingSoul &&)': cannot convert argument 1 from 'player' to 'const wanderingSoul &'
The main problem lies in the game.cpp file, below "//Battle Test" where I call "wanderingSoul wanderS(main)".
'player' is a class, and wandering soul is one as well, and the thing I don't get is how to properly pass/reference the player class since it works well when passing into functions, but not for this class constructor.
game.cpp
#include <iostream>
#include <string>
#include <ctime>
#include <cstdlib>
#include "player.h"
#include "npc.h"
#include "enemy.h"
#include "map.h"
#include "items.h"
#include "dialog.h"
/* To Do List
* Multiple chars per battle if in party.
* Add inventory & powers
* Add battles
* Finish "story" & dialogues
* Make map
* Add dialog trees (instead of if/else & switch/case)
* Add relation between characters using weighted graph
*/
void battle(player plyr, enemy nme)
{
std::cout << "You have entered a battle with " << nme.name << std::endl;
while (!plyr.dead() && !nme.dead())
{
}
}
int roll()
{
return rand() % 12 + 1;
}
int main()
{
srand(time(NULL));
std::string playerName;
char optionChoice;
int dialogChoice;
npc Lexa("Lexa", 80, 80);
BEGIN_GAME:
system("cls");
std::cout << Lexa.nameText() << "Hey... Hey, are you awake now?" << std::endl;
std::cout
<< Lexa.nameText()
<< "I was starting to get worried. You've been out for quite some time. Do you remember your name?"
<< std::endl;
INSERT_NAME:
std::cout << "(Name): ";
std::cin >> playerName;
std::cout << Lexa.nameText() << "Huh. " << playerName << ". Is that right? (y/n)" << std::endl;
std::cin >> optionChoice;
if (optionChoice != 'y' && optionChoice != 'Y')
{
//system("cls");
std::cout << Lexa.nameText() << "Please try to remember, I need to make sure you're stable. " << std::endl;
goto INSERT_NAME;
}
player main(playerName);
INTRODUCTION:
system("cls");
//Print location
initInfo(main, Lexa);
//BATTLE TEST
wanderingSoul wanderS(main);
battle(main, wanderS.ws);
//TRAVEL TEST
system("pause");
return 0;
}
enemy.h
#pragma once
#include <vector>
#include "powers.h"
#include "items.h"
#include "player.h"
//Need to include map?
class enemy
{
private:
/**Stat Properties*********
* Health: 0->100
* 0 = Death/GameOver
* Level: 1->100
* Attack: 1->10
* Defense: 1->10
* Mana: 0->100
* Affiliation: -100->100
**************************/
/*
* Add inventory
* -list of pointers to inventory items
* Add powers
* -list of pointers to powers
*/
class currPowers //Keeps track of current powers have
{
private:
public:
};
public:
unsigned int health, level, attackPWR, defensePWR, mana;
int affiliation;
std::string name;
enemy()
{
health = 100;
level = 1;
attackPWR = 1;
defensePWR = 1;
mana = 100;
affiliation = 0;
}
enemy(std::string t_name)
{
name = t_name;
health = 100;
level = 1;
attackPWR = 1;
defensePWR = 1;
mana = 100;
affiliation = 0;
}
/*
void attack(player plyr, power pwr)
{
}
*/
void defend()
{
}
bool dead()
{
if (health == 0 || level == 0)
{
if (level == 0)
{
std::cout << name << " had a heart attack." << std::endl;
}
else
{
std::cout << name << " has been defeated. Hoorah!" << std::endl;
}
return true;
}
return false;
}
std::string nameText()
{
return name + ": ";
}
};
/* ENEMY LIST
* STD/COMMON
* Wandering Soul
* Red Royal Soldier
* Wolf (Pack)
* B.A.R
* Disciples
* UNCOMMON
* Tech Soldier
* Banished Mage
* Tech Hound
* Dark Mage
* RARE
* Cyber Cyclops
* Hellhound
* Elite Androids
* Follower of The Void
* Banshee
* BOSS
* Mantis
* Mary S.
* The Summoner
* NOX-322
* The Void
*/
class wanderingSoul
{
public:
/*
Name: Wandering Soul
Health: 75/100
Level: |player level| - 1, level > 0.
Attack:
Defense:
Mana:
Affiliation:
Powers:
*/
enemy ws;
int diceRoll;
wanderingSoul(player plyr)
{
ws.name = "Wandering Soul";
diceRoll = roll(); //Rolling for health
if (diceRoll == 0)
{
ws.health = 50;
}
else if (diceRoll > 6)
{
ws.health = 100;
}
else
{
ws.level = 75;
}
diceRoll = roll(); //Rolling for level
if (diceRoll == 0)
{
ws.level = plyr.level - 1;
}
else if (diceRoll > 6)
{
ws.level = plyr.level + 1;
}
else
{
ws.level = plyr.level;
}
}
};
player.h
#pragma once
#include <vector>
#include "powers.h"
#include "items.h"
#include "enemy.h"
//Need to include map?
class player
{
private:
/**Stat Properties*********
* Health: 0->100
* 0 = Death/GameOver
* Level: 1->100
* Attack: 1->10
* Defense: 1->10
* Mana: 0->100
* Affiliation: -100->100
**************************/
//Setting everything outside private for now due to needing to access variables in other classes.
/*
* Add inventory
* -list of pointers to inventory items
* Add powers
* -list of pointers to powers
*/
class currPowers //Keeps track of current powers have
{
private:
public:
};
public:
unsigned int health, level, attackPWR, defensePWR, mana;
int affiliation;
std::string name;
player(std::string t_name)
{
name = t_name;
health = 100;
level = 1;
attackPWR = 1;
defensePWR = 1;
mana = 100;
affiliation = 0;
}
void incAffiliation(bool x)
{
if (x == true)
{
affiliation += 5;
}
else
{
affiliation -= 5;
}
}
void attack(enemy nme, power pwr)
{
}
void defend()
{
}
bool dead()
{
if (health == 0)
{
std::cout << "You are dead." << std::endl;
return true;
}
return false;
}
std::string nameText()
{
return name + ": ";
}
};
Sorry if the code is bad with many uneeded lines, I'm planning on cleaning it up soon but wanted to see if I can get a battle working with main character and enemy, although I can't tell what is the problem. The reason I am trying to pass the player (main character) class as parameter is because I'm basing the enemy's stats off of the player's stats and I'm not the best with pointers and derefencing stuff so that's most likely a problem...
Anyways, sorry for the long, eh, code but this is the first time I'm trying to make a small game through c++ and am trying to learn new things. (Well I know about classes and structures, but this is my first time using c++ for non-school/non-datastructure-implementation work)
UPDATE: Erased the game.cpp portion that was messing up and see that a problem is a 'syntax error: inditifier 'player'", so I'm trying to see how to fix that.
The problem here is you are including enemy.h in player.h and including player.h in enemy.h.
Then you include both of them in your game.cpp. This is the case of Circular dependency.
There must be more errors when you try to compile your code that you didn't share.
Anyway, you can avoid this problem using forward declaration.
Some side notes :
Since you are developing a game you need to know more about inheritance and composition. Inheritance is the case of IS-A relationship and on the other hand composition is the case of HAS-A.
So here what you are doing isn't right in matter of design, Wandering Soul is an enemy, So instead of creating an enemy inside of wanderingSoul class, inherent from class enemy.
Your enemy can have multiple gadgets and those can be another classes, so here as you can see you have a case of HAS-A situation and you can benefit from composition.
Another thing is, Player and Enemy are two separate things in your game world, So passing player to enemy class is not a good idea. You need a game controller class that controls interactions between objects of these two classes, like fighting or speaking or other things that these two might do.

Aggregate wall time of code blocks in C++

I have a large codebase and I want to manually add some timers to profile some sections of the code.
Some of those sections are within a loop, so I would like to aggregate all the wall time spent there for each iteration.
What I'd like to do in a Pythonic pseudo-code:
time_step_1 = 0
time_step_2 = 0
for pair in pairs:
start_step_1 = time.now()
run_step_1(pair)
time_step_1 += start_step_1 - time.now()
start_step_2 = time.now()
run_step_2(pair)
time_step_2 += start_step_2 - time.now()
print("Time spent in step 1", time_step_1)
print("Time spent in step 2", time_step_2)
Is there a library in C++ to do this?
Otherwise would you recommend using boost::timer, create a map of timers and then resume and stop at each iteration?
Not very advanced, but for basic time measurement, you can use std::chrono library, specifically the std::chrono::high_resolution_clock - the clock
with smallest tick period (= highest accuracy) provided by the implementation.
For some more trivial time measurement, I have used RAII classes similar to this:
#include <chrono>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <string>
class TimeMeasureGuard {
public:
using clock_type = std::chrono::high_resolution_clock;
private:
const std::string m_testName;
std::ostream& m_os;
clock_type::time_point started_at;
clock_type::time_point ended_at;
public:
TimeMeasureGuard(const std::string& testName, std::ostream& os = std::cerr)
: m_testName(testName), m_os(os)
{
started_at = clock_type::now();
}
~TimeMeasureGuard()
{
ended_at = clock_type::now();
// Get duration
const auto duration = ended_at - started_at;
// Get duration in nanoseconds
const auto durationNs = std::chrono::nanoseconds(duration).count();
// ...or in microseconds:
const auto durationUs
= std::chrono::duration_cast<std::chrono::microseconds>(duration).count();
// Report total run time into 'm_os' stream
m_os << "[Test " << std::quoted(m_testName) << "]: Total run time: "
<< durationNs << " ns, " << "or: " << durationUs << " us" << std::endl;
}
};
Of course this is a very simple class, which would deserve several improvements before being used for a real measurement.
You can use this class like:
std::uint64_t computeSquares()
{
std::uint64_t interestingNumbers = 0;
{
auto time_measurement = TimeMeasureGuard("Test1");
for (std::uint64_t x = 0; x < 1'000; ++x) {
for (std::uint64_t y = 0; y < 1'000; ++y) {
if ((x * y) % 42 == 0)
++interestingNumbers;
}
}
}
return interestingNumbers;
}
int main()
{
std::cout << "Computing all x * y, where 'x' and 'y' are from 1 to 1'000..."
<< std::endl;
const auto res = computeSquares();
std::cerr << "Interesting numbers found: " << res << std::endl;
return 0;
}
And the output is:
Computing all x * y, where 'x' and 'y' are from 1 to 1'000...
[Test "Test1"]: Total run time: 6311371 ns, or: 6311 us
Interesting numbers found: 111170
For simple time measurement cases, this might be easier than using
a whole timer library, and it's just a few lines of code, you don't
need to include lots of headers.

Having a problem writing a class in C++; undeclared identifiers

I am coding a class for the quadratic equation. I have been given the .h file, and have to write it based on that. I experience problems when I am trying to establish the "display" function, where I am getting undeclared identifier areas (as shown here):
'my_a' : undeclared identifier
'my_b' : undeclared identifier
'my_c' : undeclared identifier
'display' : function-style initializer appears to be a function definition
I would appreciate a little direction in my code. I am including the .h file at the bottom.
#include <iostream> // for cout, cin, istream, ostream
#include <cmath> // for floor
#include <string> // for class string
#include "quad.h"
using namespace std;
quadraticEquation::quadraticEquation (double initA,
double initB, double initC)
{
my_a = initA;
my_b = initB;
my_c = initC;
}
double quadraticEquation:: root1() const
{
double result = 0.0;
result= ((-1* my_b)+(sqrt((my_b*my_b)- (4*my_a*my_c)))/(2*my_a));
return result;
}
double quadraticEquation:: root2() const
{
double result = 0.0;
result= ((-1*my_b)- (sqrt((my_b*my_b)- (4*my_a*my_c)))/(2*my_a));
return result;
}
bool hasRealRoots(double root1 , double root2)
// post: returns true if an only if b*b-4*a*c >= 0.0, otherwise return false
{
bool result;
{
if (root1 >= 0.0) {
if (root2 >= 0.0){
result = true;
}
else
{
return false;}
}
}
}
void display (my_a, my_b, my_c)
// post: shows the quadratic equation like -1x^2 + 3x - 9.7
// when my_a == -1, my_b = 3, and my_c == -9.7
{
if (my_a >= 0)
cout <<my_a<< "x^2"<<;
else
cout <<"-"<< abs(my_a)<<"x^2"<<;
if(my_b >= 0)
cout << " + " << my_b << "x";
else
cout << " - " << abs(my_b) << "x";
if (my_c >= 0)
cout <<" + "<<my_c<< endl;
else
cout << " - "<<my_c<< endl;
return display;
}
And
#ifndef _QUAD_H
#define _QUAD_H
// file name: quad.h (the file on disk lists pre- and post-conditions)
class quadraticEquation {
public:
//--constructor (no default constructor for quadraticEquation)
quadraticEquation(double initA, double initB, double initC);
// post: initialize coefficients of quadratic equation initA*x*x + initB + c
//--accessors
double root1() const;
// pre: there is at least one real root: b*b-4*a*c >= 0.0
// post: returns one real root as (-b+sqrt(b*b-4*a*c)) / (2*a)
double root2() const;
// pre: there is at least one real root: b*b-4*a*c >= 0.0
// post: returns one real root as (-b-sqrt(b*b-4*a*c)) / (2*a)
bool hasRealRoots() const;
// post: returns true if an only if b*b-4*a*c >= 0.0, otherwise return false
void display() const;
// post: shows the quadratic equation like -1x^2 + 3x - 9.7
// when my_a == -1, my_b = 3, and my_c == -9.7
private:
double my_a, my_b, my_c; // the three coefficients of the quadratic equation
};
#endif
The header file shows display() taking no parameters. You've coded one that takes parameters, but you haven't included their types:
void display (my_a, my_b, my_c)
Start by making those brackets empty and things should get a lot better.
Second, display should be a member function of the class. That's how it will get access to my_a, my_b, and my_c.
void quadraticEquation::display()
Third, hasRealRoots should also be a member function of the class, taking no parameters - and your code should not just see if both numbers are positive (which makes no sense) but actually evaluate the b^2-4ac term and see if it's positive (meaning the roots of the equation will be real rather than complex.)
the use of your display function is wrong(in cpp file). just use it as
void display()
since it doesnt need params and all the params it needs are already initialised.
missed a point..
write it as void quadraticEquation::display() rather than void display()
void quadraticEquation::display (double my_a, double my_b, double my_c)
// post: shows the quadratic equation like -1x^2 + 3x - 9.7
// when my_a == -1, my_b = 3, and my_c == -9.7
{
if (my_a >= 0)
cout <<my_a<< "x^2"<<;
else
cout <<"-"<< abs(my_a)<<"x^2"<<;
if(my_b >= 0)
cout << " + " << my_b << "x";
else
cout << " - " << abs(my_b) << "x";
if (my_c >= 0)
cout <<" + "<<my_c<< endl;
else
cout << " - "<<my_c<< endl;
return display;
}