3

I'm working on a simple console application to prototype a method of calculating battle between two large units of medieval soldiers. The idea is I'll set up the calculations, and run the program several times with different parameters to get a feel for it and if it's what I want. Anyways, on to the problem.

Each of the two units is represented by a Unit class. The class includes variables for "attack", "defense", "tactics", and "unit size" as well as a few others which I'm commenting out and ignoring until I fix this issue. Here's the code for the class header:

#ifndef UNITS_H
#define UNITS_H
#include <string>
#include <iostream>

class Unit
{
  public:
      int attack;
      int defense;
      int charge;
      int brace;
      int tactics;
      int unit_size;

  public:
      bool isAlive;
      std::string name;
      Unit(std::string name_target)
      {
          name = name_target;
          attack = 1;
          defense = 1;
          charge = 1;
          brace = 1;
          tactics = 1;
          unit_size = 1;
          isAlive = true;
      }

      float GetAttack() {return (float)attack;}
      float GetDefense() {return (float)defense;}
      float GetCharge() {return (float)charge;}
      float GetBrace() {return (float)brace;}
      float GetTactics() {return (float)tactics;}
      float GetSize() {return (float)unit_size;}

      void SetAttack(int change) {attack = change;}
      void SetDefense(int change) {defense = change;}
      void SetCharge(int change) {charge = change;}
      void SetBrace(int change) {brace = change;}
      void SetTactics(int change) {tactics = change;}
      void SetSize (int change) {unit_size = change;}

      void TakeCasualties (int casualties);
      int Defend(Unit enemy, float base_chance, float base_multiplier);
      void DisplayStats();

    };

#endif // UNITS_H

Sorry if it's sloppy, but I'm a bit of an amateur.

I would include the .cpp code for the class, but everything in there works fine. I've done test runs with just the default values with no issue. The only problem I have is changing the values after they're constructed.

In main.cpp I have a function AssignStats(Unit unit_target) which I call once the two Units are constructed. I call it on each one in turn. The code for that is as follows:

void AssignStats (Unit unit_target)
{
    int x;
    cout << unit_target.name << endl;
    cout << "Value for attack?" << endl;
    cin >> x;
    cout << x << endl;
    unit_target.SetAttack(x);

    cout << "Value for defense?" << endl;
    cin >> x;
    unit_target.SetDefense(x);

    //unit_target.SetCharge(x);
    //unit_target.SetBrace(x);

    cout << "Value for tactics?" << endl;
    cin >> x;
    unit_target.SetTactics(x);

    cout << "Value for size?" << endl;
    cin >> x;
    unit_target.SetSize(x);
}

As far as I can tell, this code should work. However, when I display the stats of each Unit afterwards, it shows the default values put in by the constructor. For the life of me I can't figure out why my Set functions aren't working. I rewrote the code a little earlier to check if they were getting input right, like so:

void Unit::SetAttack()
{
    int x;
    std::cout << "Input target value for attack." << std::endl;
    std::cin >> x;
    std::cout << x;
    attack = x;
    std::cout << attack;
}

I would input 10, and each of the couts would show me 10 right back, even the one that supposedly displayed the attack variable of the class, but later on when I called DisplayStats(), it would show everything to be at default values again.

Can someone more experienced than me please clear this up?

  • I'm sure you can narrow this down. For example your class has _six_ properties each with getters and setters, but can't you reproduce the issue with just _one_? Divide and conquer should be one of your first steps in debugging, not the last (or left for us to do instead). – Lightness Races in Orbit Jun 29 '14 at 20:25
  • Good luck with this interesting & ambitious project. A couple of people have pointed out why your code doesn't work, but perhaps while you're in there you should ask yourself why your member variables are stored as integers, set as integers... but cast to float when you get them? – AAT Jun 29 '14 at 22:15
  • The reason for the casting is that I determine the outcome of the battle by first calculating a percent chance that any one soldier from one unit kills any one soldier from another. Then I roll one time for each soldier in one unit to determine how many soldiers from the other unit are killed. The equation for determining that chance involves some division, so I use floats to make sure the division stays precise. I keep the variables as integers because I want to make sure they stay whole numbers. – user3788382 Jun 30 '14 at 17:59

2 Answers2

3

I think that the problem is that function AssignStats accepts the argument by value

void AssignStats (Unit unit_target);

That is the function deals with a copy of the original object. The original object itself is not changed.

Change it the following way

void AssignStats (Unit &unit_target);
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

I tested your Set functions and they are working fine. I think the problem is the

void AssignStats (Unit unit_target);

You are passing the Unit parameter by value, not by reference. This causes a local copy of the Unit object to be made, which initializes it with new parameters.

You need to call by reference:

void AssignStats (Unit &unit_target);

That way, a reference to the original object is passed and your Set() function assignments will work on it.

Some additional advice beyond the question:

In C++ passing parameters by reference is usually preferable to passing by value, because the overhead of passing a large object by value due to copying can be substantial.

If you are using setter/getter methods to set parameters, those parameters should be declared private or protected, not public. That's one aspect of object oriented encapsulation - don't allow the parameters to be changed outside the object.

e.g you should have

//or protected if you will subclass Unit later
private:
      int attack;
      int defense;
      int charge;
      int brace;
      int tactics;
      int unit_size;
paisanco
  • 4,098
  • 6
  • 27
  • 33