C++ Class Variable not updating - c++

I'm trying to code a counter for a class I made in c++.
I'm passing an amount of time, deltaT, to a method of the Wake class, which does simply adds it onto the value already stored by a variable in the class. The code is:
void checkPlayerWakes(int deltaT){
for(size_t i = 0; i < game.getPlayer().getWakes().size(); i++){
Wake& w = game.getPlayer().getWakes().at(i);
w.age(deltaT);
}
}
However, the timer which is meant to be increasing, is remaining at 0.
The code to change the timer is:
void Wake::age(int millis) {
cout << "Updating : " << currentLife;
this->currentLife += millis;
setAlpha(((double)currentLife)/((double)lifeTime));
cout << " " << currentLife << endl;
}
E.g.
first current life: 0
second current life: 16
I know that if I were to use
Wake w = something
w.age(deltaT)
it wouldn't work because "w" would just be a copy of the object. However, that's clearly NOT my problem here? Also game.getPlayer() also returns a reference, a PLAYERSHIP&.
Last time I had a similar problem, it was solved by calling and returning references instead of just the ClassName. Am I still doing something wrong?

getWakes() needs also to return a reference, and should return vector& as opposed to vector.
I'm adding this here to make sure that this question is marked as answered.

Related

I want return type pointer but i want my function to return pointer of derive class

Dragon* Dragon::spawn() {
int x = rand() % 5;
int y;
if (!if_locked(x)) //is a function to see if that id is unlocked because i want some dragon to be generated only if you have certain xp so it will call func again until unlocked id is generated
spawn();
else
y = unlocking(m); // Y is generated form 1-5, I have assigned Id to each derive class whosoever id matches Y that pointer will be returned
if (y == 1) {
GroundDragon* pt;
return pt;
}
if (y == 2) {
WaterDragon* st;
return st;
}
if (y == 3) {
IceDragon*bt;
return bt;
}
if (y == 4) {
FireDragon* ct;
return ct;
}
if (y == 5) {
DarkDragon* dark;
return dark;
}
}
As you can see im making syntax mistakes i hope someone can guide me
The return type of function is base class and all the classes in if statement are derive class
so i can later use this function
template<class T>
void spawner(T*) {// I will spawn() fucntion as perimeter at time of call
T = new T;
}
Forgive me if im repaeting question the last time i post it didnt get attention i was expecting so i modifed my code a bit hopeful it is clear now`
int Dragon::unlocking(Mage m) {
if (m.getxp() <= 50 and m.getxp() <= 100) {
unlock[0] = 1;
cout << "Congratulation GroundDragon unlocked " << endl;
return 1;
}
if (m.getxp() > 100 and m.getxp() < 150) {
unlock[1] = 1;
cout << "Congratulation WaterDragon unlocked " << endl;
return 2;
}
if (m.getxp() > 150 and m.getxp() < 175) {
unlock[2] = 1;
cout << "Congratulation IceDragon unlocked " << endl;
return 3;
}
if (m.getxp() > 175 and m.getxp() < 500) {
unlock[3] = 1;
cout << "Congratulation FireDragon unlocked " << endl;
return 4;
}
if (m.getxp() > 500) {
unlock[4] = 1;
cout << "Congratulation DarkDragon unlocked " << endl;
return 5;
}
}
bool Dragon::if_locked(int x) {
if (unlock[x] == 1) {
return true;
}
else
return false;
}
*Im not comfortable with smartpointer(i have never used them before but i would love to use them if you show me how to call it main *
I used raw pointer but it is still showing me errors please help mw
The idea is sound, it's just the execution that failed.
If you want to have a factory function that will return different objects that will then behave polymorphically, this is perfectly fine, with one important thing - you need to return actual objects.
Your factory function has a return type of Dragon*. This means that whatever value you return, it will be a pointer pointing to (some sort of a) Dragon. However, the value of that pointer can point to an object that is actually an instace of FireDragon, IceDragon etc. When you create an instance of such an object, the pointer to such instance can then get converted to the appropriate return type and returned.
In your case though, while you're creating temporary objects of type pointer-to-some-sort-of-dragon, you're not actually filling them with instances. They all are created with an unspecified value, and that value is then converted to an unspecified value of type Dragon*, with no way to extract the information which type it was converted from.
So, in order to make it work in a usual fashion, we just need to create a new instance of appropriate type and return it. We don't ever want to return raw pointers from functions when transferring ownership, so std::unique_ptr is a much better alternative:
std::unique_ptr<Dragon> Dragon::spawn() {
int x = rand() % 5;
/* note - this bit of code doesn't make any sense whatsoever
int y;
if (!if_locked(x)) //is a different function
spawn();
else
y = unlocking(m); //is also a different function
*/
// note that `rand() % 5` will produce values 0 through 4.
switch(x) {
case 0: return std::make_unique<GroundDragon>();
case 1: return std::make_unique<WaterDragon>();
case 2: return std::make_unique<IceDragon>();
case 3: return std::make_unique<FireDragon>();
case 4: return std::make_unique<DarkDragon>();
}
}
Now you don't need the spawner function at all; you can directly use the returned value.
I think the first important lesson to give is about initializing pointers.
The line
GroundDragon* pt;
declares that there is a pointer to a GroundDragon object, so far so good. However, this does not create an object.
As an analogy: you created a direction sign that is able to point into the direction of a village, but you do not build an actual village for it to point towards. And right now, it just points into some random direction.
Being uninitialized, pt contains a random value, not the address of an existing object of type GroundDragon. Doing anything with it will most likely result in bad things (it is undefined behaviour in particular).
In order to initialize it, you would write it like
GroundDragon* pt = new GroundDragon;
This creates an objects of type GroundDragon on the heap and assigns it's address to pt.
Also note that every new needs a delete to keep the memory clean, just to mention this preemptively.
This is very essential knowledge - make sure to understand this.
I wanted to write this in order to show you how to work with raw pointers, as an addition to the answer of Bartek Banachewicz, who did not show the way to initialize raw pointers. What he then does, using smart pointers, is clearly a way better approach than using raw pointers, though. However, I'd say that it is quite important that you are also able to work with raw pointers. Make sure to be able to do both in the long run, and use smart pointers whenever you can.
Edit: Now for the other part of your code,
int x = rand() % 5;
int y;
if (!if_locked(x)) //is a function to see if that id is unlocked because i want some dragon to be generated only if you have certain xp so it will call func again until unlocked id is generated
spawn();
else
y = unlocking(m);
First of all, please be aware that calling spawn(); ignores the return value. Which means, it has no effect at all. What you probably wanted to write is return spawn();.
Second, if(!if_locked(x)) seems to me to be the contrary of what it should be. "if not locked" means "if unlocked", and in that case, it should not try it again but instead proceed, right?
And, is the Mage m that you give to unlocking a member of Dragon? Sounds like it rather should be a pointer, if you don't especially want a relationship like Dragon owns Mage.
In any case, I would keep unlocking out of spawn. A method like spawn says that it is good for spawning. Especially printing that something is unlocked is not something I would intuitively understand a part of the spawning process. Also, I would name it differently, as "unlocking" is a status rather than a command. Go like check_for_new_unlocks or something like that, which sounds like a command. And do it separately from spawn.
Also, note that you check for narrow experience intervals - are you sure that it can't happen that an interval is never triggered, as the character might advance over the interval with never calling the method in between?
Furthermore, I'd call the array that says if something is unlocked differently. "unlock" sounds like a command. How about "available"?
Also, I find the recursive call of spawn to be less readable as trying out other values for x, but that is opinion. I'd go like
int x = rand() % 5;
while(not available[x])
{
x = rand() % 5;
}
Maybe this can be done more clever, though, based on the actual mechanics. You could create the random variable like int x = rand() % total_available(); for instance.
Note that a lot of this is somewhat opinion based. In this regard, I want to point you towards CodeReview - as soon as your code works correctly, you might want to post it there for people to help you improve it in several different regards.

Why are my variables giving a different value when they are printed outside of the class I set them in?

I am making fairly new to C++ and I am using it to make a text based game for a school project. However during the first section of the game the player answers questions by entering the number shown beside the answer they choose. However when I tested the variables the input going to using std::cout they return different values depending on where they are outputted. If I outputted them in the class I am using to set them (Introduction) the they return the correct value such as 1 or 3 etc. However when I output them in any file other than Introduction.cpp, the value displayed is -858993460 for all of the values. I get the same result from Main.cpp when I call them in my main function and if I call them from another function in a different class to Introduction.
This is an example of some of the code used to get input from the user:
void Introduction::CharacterCreation()
{
Universal universal;
std::fstream creation("Introduction_CharacterCreation.txt");
universal.line = 5;
for (int i = 0; i < universal.line; i++)
{
if (i > 0)
{
std::getline(creation, universal.displayText);
std::cout << universal.displayText << std::endl;
}
if (i == 4)
{
std::cout << std::endl;
std::cin >> universal.gender;
while (universal.gender <= 0 || universal.gender >= 3)
{
std::cout << "Please make a valid choice" << std::endl;
std::cin >> universal.gender;
}
}
}
// Code cut out here
}
The gender variable is an int declared in the Universal class, and the user is prompted to enter 1 for male or 2 for female by text pulled from a separate file. If the input is not 1 or 2 then a while loop forces the player to keep re-answering the question until they enter 1 or 2. The line variable is also an int however that is used for the for loops to ensure the right lines are read by the program.
To output the gender variable this is the code I use:
std::cout << gender << std::endl;
There is no universal. as it is being called within the Universal class itself.
This has confused me massively and I can't get my head around what is causing the problem. Any help or explanation would be great, thanks in advance.
Short answer: you're declaring a Universal object in your CharacterCreation() method. When this function exits since the scope of the universal variable was local so the entire object is destroyed.
Whatever you are outputting is just uninitialized garbage. It could really be any number depending on what system is compiling / running the program. To test this right after you input the gender, while still inside the function, try running
std::cout << universal.gender << std::endl;
This should output just fine.
There are a lot of ways you can go about fixing this. Since you didn't post where you call this method or your Universal class I can't say for sure. But I can speculate one such solution which is to declare the Universal object outside the method and then pass it in as a parameter:
Universal universal = Universal();
Introduction::CharacterCreation(universal);
std::cout << universal.gender << std::endl;
And just declare your function header to accept a Universal object:
void Introduction::CharacterCreation(Universal & universal)
{
//code here
}

std::vector<> assignment operation not working; need 'clear' operation first

I am confused by what I thought should be a very simple operation. I call a method that creates a std::vector and returns it. Then I set an existing std::vector to that result, expecting the = operator to work. The code looks like this:
std::vector<BTLECharDecl> charDeclList;
charDeclList.clear();
// get the services on the agent
// It loads the discovered services into the class variable 'serviceList'
if((result = discoverServices()) != rc_SUCCESS)
{
std::cout << "Discovering service failed. Function returned message "
<< eResultCode2str(result) << "(" << hex << result << dec << ")" << endl;
return result;
}
if(serviceList.size() > 0)
{
for(uint16 i = 0; i < serviceList.size(); i++)
{
// Get chararcteristic Declaration List as Objects for each service
startHandle = serviceList.at(i).getServiceData().startHandle;
endHandle = serviceList.at(i).getServiceData().endHandle;
if(startHandle < endHandle)
{
// !! WHY DO I NEED THIS clear()?? !!
charDeclList.clear();
charDeclList = discoverCharDecl(serviceList.at(i).getServiceData().startHandle, endHandle);
}
If I do not invoke the charDeclList.clear() method before the call to the method that returns this type of object, I will get leftover garbage from previous loops. Not always, but sometimes. I would have expected the assignment operator to completely replace whatever was there with that which is returned by the called method. What is wrong with my thinking? (Invoking the clear() solves the problem but it is unsettling.) Working with MS Visual Studio 2008.

C++ After Function Call and Function Completion, Game Crashes Entirely

I've been having an issue with a game I've been making in my C++ game programming class for school. For some reason, after calling a function which I'm using to manage the inventory based stuff, the function seems to complete and work (I think this because I put in cout commands at the end of it and they printed correctly, also the function runs twice in a row, and they both run), my entire game crashes and doesn't reach the next line. I tried commenting out all the code in the function and it still crashed. I commented out the function calls and it worked, but I still can't tell what is wrong with it. I'll put the code for the function and the section were I make the calls:
string inventoryFunction(int h, string ab)
{
if(h == 1)
inventory.push_back(ab);
else
if(h == 2)
{
for(int i=0; i < inventory.size(); i++)
{
if(inventory[i] == ab)
inventory[i].erase();
}
}
else
if(h == 3)
{
cout << inventory[0];
for(int i=1; i < inventory.size(); i++)
cout << ", " << inventory[i];
}
}
The function call:
if(answer.find("village") != string::npos)
{
cout << endl;
cout << "While looking around your village,\nyou found a stone sword and a cracked wooden shield!" << endl;
inventoryFunction(1, "stone sword");
inventoryFunction(1, "cracked wooden shield");
cout << "Would you like to set off on your adventure now?" << endl;
cin >> answer2;
capitalizeLower(answer2);
Not sure there's anything there likely to cause a crash, my advice would be to single-step your code in the debugger to see where it's falling over. It's quite possible the bug is somewhere totally different and it's just being exacerbated by the function calls modifying the vector.
That's the nature of bugs unfortunately, you can never really tell where they're actually coming from without looking closely :-)
However, there are a couple of issues with the code that I'd like to point out.
First, with regard to:
inventory[i].erase();
That doesn't do what you think it does. inventory[i] is the string inside your vector so it's simply erasing the string contents.
If you want to remove the string from the vector, you need something like:
inventory.erase (inventory.begin() + i);
Second, I'd tend to have three separate functions for addToInventory, removeFromInventory and listInventory.
It seems a little ... unintuitive ... to have to remember the magic values for h to achieve what you want to do, and there's no real commonality in the three use cases other than access to the inventory vector (and that's not really reason enough to combine them into the same member function).
On top of that, your function appears to be returning a string but you have no actual return statements and, in fact, none of the three use cases of your function require anything to be passed back.
The signature is better off as:
void inventoryFunction(int h, string ab)
In terms of the second and third points above, I'd probably start with something like:
void addToInventory (string item) {
inventory.push_back(ab);
}
void removeFromInventory (string item) {
for (int i = 0; i < inventory.size(); i++) {
if (inventory[i] == ab) {
inventory.erase (inventory.begin() + i);
break;
}
}
void listInventory () {
cout << inventory[0];
for (int i = 1; i < inventory.size(); i++)
cout << ", " << inventory[i];
}
You may also want to look into using iterators exclusively for the second and third functions rather than manually iterating over the collection with i.
It'll save you some code and be more "C++ic", a C++ version of the "Pythonic" concept, a meme that I hope will catch on and make me famous :-)
So by changing the inventoryFunction to a void function like #Retired Ninja said, the crash has stopped occurring and now the program is working great.
Also, #paxdiablo pointed out that I was using the inventory[i].erase() thing incorrectly, so thanks a bunch to him, because now I won't have to come back on here later to try to fix that :D
string inventoryFunction(int h, string ab)
should return a string but does not have any return statements. Of course it works, after you change it to a void function, which correctly does not return anything. Interesting is, that you are able co compile this code without an error - normally a compiler would show you this problem.

adding an array of class objects into one master class object

for a project I had to create a class that had variables for feet and inches, and had a method to add these variables together from object 1 and object 2, then object 3, 4, and so on.
CDistance CDistance::add(const CDistance& yourDist) const
{
CDistance total;
total.feet += yourDist.feet;
total.inches += yourDist.inches;
/*if (total.inches > 12)
{
total.feet += (total.inches / 12);
total.inches = total.inches % 12;
}*/
return total;
}
that's the method I have for adding, and here is a function in the main source file, where I process each class
void printAndAdd(const CDistance distList[], int size)
{
CDistance new_total;
new_total = distList[0].add(distList[1].add(distList[2].add(distList[3].add(distList[4]))));
new_total.printDist();
}
And here is the method I use to print out the data on screen
void CDistance::printDist() const
{
cout << "Feet: " << this->feet << "\n\n";
cout << "Inches: " << this->inches << "\n\n";
}
I thought about using a for loop, for that 2nd line, but I'm having a bit of a problem. Whenever I print the data out, it's 0. As if the add function isn't working, which I'm not quite sure I even understand what I did. From what I think I'm doing, it's creating a new obejct, adding the variables from the referenced to object to the created object, that commented out section is a section I just took out for now and will add later, and then it returns the object. When I call the function in my main source file it would set the object new_total equal to the sum of object 0, 1, 2, 3, and 4. Am I close, or way off to what's actually happening? I should also explain that I've only been programming for about a year, it's really intriguing to me, but naturally difficult at times, and I'm still trying to grasp my hands around the idea of classes in c++.
The problem is that you never use the instance variables when adding. Instead you always start from a freshly minted object. Try this:
CDistance CDistance::add(const CDistance& yourDist) const
{
CDistance total(*this);
total.feet += yourDist.feet;
total.inches += yourDist.inches;
this->feet += yourDist.feet;
this->inches += yourDist.inches;
return total;
}
I've done some playing with your code and it looks like this line should is incorrect:
CDistance total;
The value of total is never initialized and is therefore always going to be whatever your default constructor has defined it to be (probably 0/0). Thus, the result of that call will always end up whatever was passed to the input. I think you meant to do this:
CDistance total = *this;
That will copy the current values for feet an inches into the temp and then the following lines will add the input. Passing through the chain of calls like you do should now concatenate the additions as expected.