patterncppMinor
Multiclassing and updating each of its component classes whenever it changes
Viewed 0 times
eachupdatingwhenevermulticlassingitschangesclassesandcomponent
Problem
A
Now watch what happens here:
Output:
`Borg's coordinates are (0, 0, 0)
Multiclass character can consist of any number of component classes. For example, if Fighter, Wizard, and Monk are character classes, then a Multiclass can be all 3 and having all three capabilities. Because multiple inheritance is impossible due to the unlimited number of such component classes, I'm using the Composite Pattern.Now watch what happens here:
#include
#include
#include
struct Coordinates {
int x, y, z;
void print() const {std::cout componentClasses; // Composite Pattern for the component classes
using CharacterClass::CharacterClass;
Multiclass (const std::string& name, int hitPoints) : CharacterClass (name, hitPoints) {
// For simpicity, assume Fighter/Wizard/Monk is the Multiclass.
componentClasses.push_back (new Fighter(name, hitPoints));
componentClasses.push_back (new Wizard(name, hitPoints));
componentClasses.push_back (new Monk(name, hitPoints));
}
Wizard* getWizard() const {return static_cast(componentClasses[1]);}
void castsFireBall (LivingBeing& target) {getWizard()->castsFireBall(target);}
};
inline int distanceBetween (const Coordinates& c1, const Coordinates& c2) {
return static_cast ( sqrt (pow(c1.x - c2.x, 2) + pow(c1.y - c2.y, 2) + pow(c1.z - c2.z, 2)) );
}
inline int distanceBetween (const LivingBeing& being1, const LivingBeing& being2) {
return distanceBetween (being1.coordinates, being2.coordinates);
}
void Wizard::castsFireBall (LivingBeing& target) {
if (distanceBetween(*this, target) < 10) {
std::cout << name << " is caught in his own fireball because his coordinates are \n";
coordinates.print();
}
else
std::cout << target.name << " is hit by the fireball.\n";
}
int main() {
Multiclass rex ("Rex", 50);
Fighter borg ("Borg", 80);
borg.showCoordinates();
rex.moves ({100, 120, 0});
rex.showCoordinates();
rex.castsFireBall(borg);
}Output:
`Borg's coordinates are (0, 0, 0)
Solution
Code Review
You need to start looking at class/struct differenes
This looks fine as a structure:
But this looks more like a class
You don't want other people reaching and changing the hit points of a character without using one of the offical mechanisme: like
Print routines:
These are fine. But also add the standard
Learn about smart pointers
Modern C++ does not use many RAW pointers (if you see them you are looking at people that are writting C with the C++ compiler). Your pointers should be held inside smart pointers (or resource aware objects of some type) that know how/when to deallocate them:
Here:
A vector of pointers (OK I can live with that).
Pushing things created with new into it. Not that cool but I am looking for the point where these objects are destroyed and I see no destructor.
Design
I think you have some fundamental design flaws:
I think they basically stem from here. A character class is not a living being. A class is an attribute of sentient being that has taken the time to train for those abilities. i.e. A character may have "no class" as a child. But he trains with the local militia and gains some skills as a fighter (does not mean he "is-a" a fighter but rather has some skills as a fighter). Subsequently the character rescues a monk and as payment the monk imparts some training to the character that gives him more skills.
So to me the "class" of a character imparts some set of skills that a character can utilize when taking an action.
Other Classes you may need.
```
class Action
{
public:
virtual ~Action() {}
};
class SkillAtAction;
class SkillSet
{
public:
SkillAtAction& canDoAction(Action const& action);
};
class SkillAtAction
{
public:
virtual int skillLevel() = 0;
virtual void performAction(LivingBeing& src, Action const& action) = 0;
};
class defaultInabilityToDoAction: public SkillAtAction
{
public:
virtual
You need to start looking at class/struct differenes
This looks fine as a structure:
struct Coordinates {
int x, y, z;
void print() const {std::cout << "(" << x << ", " << y << ", " << z << ").\n";}
};But this looks more like a class
struct LivingBeing {
std::string name;
int hitPoints;You don't want other people reaching and changing the hit points of a character without using one of the offical mechanisme: like
void LivingBeing::inflictDammage(int damage)
{
if (itenary.find("MagicRingOfStinky") { // If you don't go through the inflictDamage
// interface then people may forget
// to check for the stinky ring!!
damage = max(0, damage-2);
}
hitPoints -= damage;
}Print routines:
These are fine. But also add the standard
operator<<() to make it easy to print to any stream.friend std::ostream& operator<<(std::ostream& str, Coordinates const& c)
{
c.print(str); // Need to modify print to take a stream.
return str;
}Learn about smart pointers
Modern C++ does not use many RAW pointers (if you see them you are looking at people that are writting C with the C++ compiler). Your pointers should be held inside smart pointers (or resource aware objects of some type) that know how/when to deallocate them:
Here:
std::vector componentClasses;A vector of pointers (OK I can live with that).
componentClasses.push_back (new Fighter(name, hitPoints));
componentClasses.push_back (new Wizard(name, hitPoints));
componentClasses.push_back (new Monk(name, hitPoints));Pushing things created with new into it. Not that cool but I am looking for the point where these objects are destroyed and I see no destructor.
Design
I think you have some fundamental design flaws:
struct CharacterClass : LivingBeing {
using LivingBeing::LivingBeing;
};I think they basically stem from here. A character class is not a living being. A class is an attribute of sentient being that has taken the time to train for those abilities. i.e. A character may have "no class" as a child. But he trains with the local militia and gains some skills as a fighter (does not mean he "is-a" a fighter but rather has some skills as a fighter). Subsequently the character rescues a monk and as payment the monk imparts some training to the character that gives him more skills.
So to me the "class" of a character imparts some set of skills that a character can utilize when taking an action.
class Character: public LivingBeing
{
std::vector skills;
public:
// As character gets more training/experience we can add new
// skills. Like FighterLevel1 skills FighterLevel2 skills
// etc.
void undertakeTraining(SkillSet& newSkills)
{
skills.push_back(&newSkills);
}
// When we perform an action we ask each skill we have learned
// how well that skill can do the action (both Monk and Fighter
// can attack with bare hands but a monk has a higher skill level
// at unarmed combat, but a fighter has a higher skill level at
// armed combat).
//
// So find the skill set with the highest profeciency at a task
// and use that.
//
// Note: The default skill at an action is `defaultInabilityToDoAction`
// This will return `skillLevel()` of 0 (or something obviously low)
// If you use this SkillAtAction to perform the task it is going
// to not be affective. So if you try and perform the action "FireBall"
// and you have no wizzard skill training then you are not going to
// find any ability to perform the action.
void performAction(Action const& action)
{
static NoSkillAtAction defaultInabilityToDoAction;
std::reference_wrapper skillAtAction = defaultInabilityToDoAction;
for(SkillSet* skill: skills) {
SkillAtAction& canDoAction = skills.canDoAction(action);
if (canDoAction.skillLevel() > skillAtActionskillLevel()) {
skillAtAction = canDoAction;
}
// Now Found the skill set that does the action at the highest Level
skillAtAction.performAction(*this, action);
}
};Other Classes you may need.
```
class Action
{
public:
virtual ~Action() {}
};
class SkillAtAction;
class SkillSet
{
public:
SkillAtAction& canDoAction(Action const& action);
};
class SkillAtAction
{
public:
virtual int skillLevel() = 0;
virtual void performAction(LivingBeing& src, Action const& action) = 0;
};
class defaultInabilityToDoAction: public SkillAtAction
{
public:
virtual
Code Snippets
struct Coordinates {
int x, y, z;
void print() const {std::cout << "(" << x << ", " << y << ", " << z << ").\n";}
};struct LivingBeing {
std::string name;
int hitPoints;void LivingBeing::inflictDammage(int damage)
{
if (itenary.find("MagicRingOfStinky") { // If you don't go through the inflictDamage
// interface then people may forget
// to check for the stinky ring!!
damage = max(0, damage-2);
}
hitPoints -= damage;
}friend std::ostream& operator<<(std::ostream& str, Coordinates const& c)
{
c.print(str); // Need to modify print to take a stream.
return str;
}std::vector<CharacterClass*> componentClasses;Context
StackExchange Code Review Q#75674, answer score: 2
Revisions (0)
No revisions yet.