I have a class called HealthPoints
that has hp
and max_hp
members. I want to overload the
operator so it will work like this:
HealthPoints healthPoints1;
healthPoints1 -= 150; /* healthPoints1 now has 0 points out of 100 */
HealthPoints healthPoints2(150);
healthPoints2 -= 160; /* healthPoints2 now has 0 points out of 150 */
healthPoints2 = healthPoints1 160; /* healthPoints2 now has 100 points out of 100 */
I succeeded in making it work, but only in a specific order. If I put the number before the object, is there any way to make it recognize the number between the two of them and act accordingly? The way it works at the moment, I get that healthPoints2
now has 160 points out of 160.
HealthPoints
class:
class HealthPoints {
public:
static const int DEFAULT_MAXHP=100;
static const int DEFAULT_HP=100;
static const int MINIMUM_MAXHP=1;
static const int MINIMUM_HP=0;
explicit operator int() const;
HealthPoints(int maxHP=HealthPoints::DEFAULT_MAXHP);
~HealthPoints() = default; // Destructor set to default
HealthPoints(const HealthPoints&) = default; // Copy Constructor set to default
HealthPoints& operator=(const HealthPoints&) = default; // Assignment operator set to default
HealthPoints& operator =(const HealthPoints& HP);
HealthPoints& operator-=(const HealthPoints& HP);
class InvalidArgument {};
private:
int m_maxHP;
int m_HP;
friend bool operator==(const HealthPoints& HP1, const HealthPoints& HP2);
friend bool operator<(const HealthPoints& HP1, const HealthPoints& HP2);
friend std::ostream& operator<<(std::ostream& os, const HealthPoints& HP);
};
HealthPoints::HealthPoints(int maxHP) {
if(maxHP < HealthPoints::MINIMUM_MAXHP) {
throw HealthPoints::InvalidArgument();
}
this->m_maxHP=maxHP;
this->m_HP=m_maxHP;
}
HealthPoints operator (const HealthPoints& HP1, const HealthPoints& HP2) {
return HealthPoints(HP2) =HP1;
}
HealthPoints operator-(const HealthPoints& HP1, const HealthPoints& HP2) {
return HealthPoints(HP1)-=HP2;
}
HealthPoints& HealthPoints::operator =(const HealthPoints& HP) {
if(this->m_HP HP.m_HP>this->m_maxHP) {
this->m_HP=this->m_maxHP;
} else {
this->m_HP =HP.m_HP;
}
return *this;
}
HealthPoints& HealthPoints::operator-=(const HealthPoints& HP) {
if(this->m_HP-HP.m_HP>HealthPoints::MINIMUM_HP) {
this->m_HP-=HP.m_HP;
} else {
this->m_HP=HealthPoints::MINIMUM_HP;
}
return *this;
}
CodePudding user response:
In this statement:
healthPoints2 = healthPoints1 160;
Your
operator is creating a new HealthPoints
object that is a copy of healthPoints1
, thus the object's m_maxHP
is set to 100
. Then you are adding 160
to that object, increasing its m_HP
but preserving its m_maxHP
. Then you are assigning that object to healthPoints2
, copying both m_HP
and m_maxHP
values. That is why the m_maxHP
of healthPoints2
changes from 150
to 100
.
In this statement:
healthPoints2 = 160 healthPoints1;
Your
operator is creating a new HealthPoints
object whose m_maxHP
is set to 160
. Then you are adding healthPoints1
to that object, increasing its m_HP
but preserving its m_maxHP
. Then you are assigning that object to healthPoints2
, copying both m_HP
and m_maxHP
values. That is why the m_maxHP
of healthPoints2
changes from 150
to 160
.
If you want your operator
s to update only the m_HP
and not change the m_maxHP
, you need to add overloads that accept int
values instead of HealthPoints
objects, eg:
HealthPoints& HealthPoints::operator =(int value) {
m_HP = std::min(m_HP value, m_maxHP);
return *this;
}
HealthPoints& HealthPoints::operator-=(int value) {
m_HP = std::max(m_HP - value, HealthPoints::MINIMUM_HP);
return *this;
}
HealthPoints operator (const HealthPoints& HP, int value) {
return HealthPoints(HP) = value;
}
HealthPoints operator (int value, const HealthPoints& HP) {
return HealthPoints(HP) = value;
}
HealthPoints operator-(const HealthPoints& HP, int value) {
return HealthPoints(HP) -= value;
}
HealthPoints operator-(int value, const HealthPoints& HP) {
return HealthPoints(HP) -= value;
}
And then, mark the HealthPoints(int)
constructor as explicit
to avoid unwanted implicit conversions when passing int
values to parameters that are expecting HealthPoints
objects.
CodePudding user response:
I'm not completely sure of the logic of your HealthPoints
class, so double check my code below. My point, though, is to implement:
friend HealthPoints operator (const HealthPoints& other, int value);
friend HealthPoints operator (int value, const HealthPoints& other);
You actually just need to implement the first one, and have the second one use it:
HealthPoints operator (const HealthPoints& hp, int value) {
HealthPoints ret{hp};
ret.m_HP = std::min(ret.m_maxHP, ret.m_HP value);
return ret;
}
HealthPoints operator (int value, const HealthPoints& hp) {
return hp value;
}
You can see it here in action:
int main() {
HealthPoints hp1{100};
hp1 -= 50;
std::cout << "hp1: " << hp1 << "\n";
auto hp2{hp1 10};
std::cout << "hp2: " << hp2 << "\n";
auto hp3{10 hp2};
std::cout << "hp3: " << hp3 << "\n";
}
// Outputs:
// hp1: (max_HP = 100, HP = 50)
// hp2: (max_HP = 100, HP = 60)
// hp3: (max_HP = 100, HP = 70)