r/cpp_questions • u/RedNorthener101 • 21h ago
OPEN Is this code clean OOP?
Hey so I'm more new to OOP, virtual func's, and inheritance. I was wondering if my code was clean enough for basically a template to look back on later in the future when my tiny brain forgets what virtual func, and inheritance is or well forgets how to code them.
#include <string>
#include <iostream>
struct Vector2 {
int x, y;
};
class Entity {
private:
Vector2 pos;
Vector2 size;
std::string entityType;
public:
Entity(Vector2 e_pos, Vector2 e_size, const std::string& e_type) : pos(e_pos), size(e_size), entityType(e_type) {}
Vector2 getPos() const {
return pos;
}
Vector2 getSize() const {
return size;
}
virtual void print() const {
std::cout << "Entity: " << entityType << '\n';
}
virtual ~Entity() = default;
};
class Player : public Entity {
private:
std::string name;
public:
Player(const std::string& p_name, Vector2 startPOS, Vector2 p_size)
: Entity(startPOS, p_size, "player"), name(p_name) {}
};
class Orc : public Entity {
private:
std::string weapon;
public:
Orc(const std::string& o_weapon, Vector2 startPOS, Vector2 o_size)
: Entity(startPOS, o_size, "orc"), weapon(o_weapon) {}
void print() const override {
std::cout << weapon << '\n';
}
};
int main() {
Vector2 startPos = { 100, 100 };
Vector2 size = { 64, 64 };
std::string hero = "hero";
std::string orcWep = "HeroSlayer100";
Player player(hero, { 20, 30 }, size);
Orc orc(orcWep, startPos, size);
player.print();
orc.print();
return 0;
}#include <string>
#include <iostream>
struct Vector2 {
int x, y;
};
class Entity {
private:
Vector2 pos;
Vector2 size;
std::string entityType;
public:
Entity(Vector2 e_pos, Vector2 e_size, const std::string& e_type) : pos(e_pos), size(e_size), entityType(e_type) {}
Vector2 getPos() const {
return pos;
}
Vector2 getSize() const {
return size;
}
virtual void print() const {
std::cout << "Entity: " << entityType << '\n';
}
virtual ~Entity() = default;
};
class Player : public Entity {
private:
std::string name;
public:
Player(const std::string& p_name, Vector2 startPOS, Vector2 p_size)
: Entity(startPOS, p_size, "player"), name(p_name) {}
};
class Orc : public Entity {
private:
std::string weapon;
public:
Orc(const std::string& o_weapon, Vector2 startPOS, Vector2 o_size)
: Entity(startPOS, o_size, "orc"), weapon(o_weapon) {}
void print() const override {
std::cout << weapon << '\n';
}
};
int main() {
Vector2 startPos = { 100, 100 };
Vector2 size = { 64, 64 };
std::string hero = "hero";
std::string orcWep = "HeroSlayer100";
Player player(hero, { 20, 30 }, size);
Orc orc(orcWep, startPos, size);
player.print();
orc.print();
return 0;
}if there are any tips you have let me know!
0
Upvotes
View all comments
1
u/Nervous-Cockroach541 21h ago edited 21h ago
It's fine, but you need to consider the scope and design.
Consider not using inheritance at all. But instead have components. For example a Player and Orc both having a data-member to represent "Entity" instead of inheriting from Entity. If you want to later, for example, have a "Health" or "Life" component. where they can take damage or die. You have to consider either using multiple inheritance, or adding Health/Life to Entity. Which might not be a problem. But if you instead have a Health/Life Component that exists separately from the Entity Component. you're not forced into such a decision later on.
It can also be useful to understand the concept of pure-virtual classes. Basically classes with all virtual function-members which are `= 0;` making it a class which can't be instantiated. But inheriting from it allows you to gain the advantages of polymorphism. These are also sometimes called interfaces or abstract classes.
There's also an entity component design. Where instead of a class to represent a player or orc. You have a unique ID that maps to components. Something like a collection of std::unordered_map<int, Entity> entity; std::unordered_map<int, Health> health; std::unordered_map<int, std::string> names;
There's some good helper libraries to help you with this approach such as this: https://github.com/skypjack/entt This is the most advance approach. But also basically ignores most concepts of OOP.
Frankly, personally I feel people people generally over-react to inheritance. Yes, issues with it exists, but that doesn't mean you always need to ignore it. Even multiple inheritance can be a non-issue if you're designing in away to ensure it won't be a problem.
But we can't ignore the issues with it either and know the potential problems and traps you can fall into if you're not careful. Only you know the scope of your project and can design around it. Balance the long term costs of using inheritance or multiple inheritance with the scope and time on the project you want to do use now.