1

I handed in a remake of an old game in C++ using SDL2 for a programming course that I took, I passed but the professor left me some feedback and there is one part that I couldn't understand. It made sense when he said it and when I tried implementing it I got stuck.

I have an Enemy class which is an abstract class and then many different enemies that inherit from that class. The issue is that when I am creating an enemy I have to pass in its constructor my ProjectileManager* instance that I have created in my main controlling file called Game.cpp. He said that since all enemies need the ProjectileManager it would be smarter to just add it in the Enemies class as protected and have the other children inherit it.

The issue is that the instance is created in the Game.cpp and I have to pass that specific instance since that is the one that I am Drawing and Updating for. Is there a way to do that?

Edit: Here is some of the code
Game.cpp:

void Game::Initialize() { m_pProjectileManager = new ProjectileManager(); } 

The projectile manager is what Updates and Draws all the projectiles as well as their hit logic etc. It has an array that manages all the projectiles. Every time an enemy wants to shoot it would access the projectile manager (that I passed in its constructor) and trigger the shoot function of the specific enemy:

void Plant::Shoot(const Point2f& target) { if (m_CanShoot) { m_CurrentState = Plant::PlantState::shooting; m_pProjectileManager->AddProjectile((new PlantProjectile(Point2f{ m_Shape.left, m_Shape.bottom }, target))); m_CanShoot = false; m_TimeSinceLastShot = 0; } } 

Finally this is the Enemy class that I have right now:

class Enemies { public: virtual ~Enemies() = 0; virtual void Update(float elapsedSec, const Point2f& playerPos, Level& level) = 0; virtual void Draw() const = 0; virtual Rectf GetShape() const = 0; virtual float GetHealth() const = 0; virtual void Damage(float damage) = 0; protected: ProjectileManager* m_pProjectileManager; }; 
11
  • With a pointer. Commented Aug 18, 2022 at 16:33
  • If the ProjectileManager* instance is created in your main, or some other bigger enclosing scope Game.cpp, and needs to be shared between different enemies, then the professor is wrong, and you should pass that ptr in the Enemy constructor. Anyway, code please, otherwise we can speculate and misunderstand each other. Commented Aug 18, 2022 at 16:33
  • In any case, you can't create instances of abstract classes. Commented Aug 18, 2022 at 16:35
  • 2
    You cannot create abstract classes. That's what makes them abstract. Commented Aug 18, 2022 at 16:38
  • The terminology in the title "create an instance of a variable in an abstract class" is very close to "create an instance of an abstract class" which is a totally different question and answer. But for this question, you'll probably do well to show some code of what you want to do. As either you'll figure it out when writing the code or else it'll be easier to help with what specifically is tripping you up. Commented Aug 18, 2022 at 16:38

1 Answer 1

1

If there is only ever one ProjectileManager object in the entire game, there are two "easy" ways to accomplish this, and both have some drawbacks.

First, you could make it a singleton:

class ProjectileManager { // stuff.... static ProjectileManager* instance() { static ProjectileManager one; return &one; } }; // Game.cpp void Game::Initialize() { // m_pProjectileManager = new ProjectileManager(); m_pProjectileManager = ProjectileManager::instance(); } // Enemy impl void Plant::Shoot(const Point2f& target) { if (m_CanShoot) { m_CurrentState = Plant::PlantState::shooting; ProjectileManager::instaince()->AddProjectile((new PlantProjectile(Point2f{ m_Shape.left, m_Shape.bottom }, target))); m_CanShoot = false; m_TimeSinceLastShot = 0; } } 

Or you could make it static in Enemy, and provide a function to set it:

class Enemy { public: static SetProjectileManager(ProjectileManager* projectile_manager) { m_pProjectileManager = projectile_manager; } protected: static ProjectileManager* m_pProjectileManager; }; // Game.cpp void Game::Initialize() { m_pProjectileManager = new ProjectileManager(); Enemy::SetProjectileManager(m_pProjectileManager); } 

Without seeing the entire codebase it's hard to know which is the better (of these two) recommendations. Neither is perfect by any means. Singletons have a lot of drawbacks and I hesitate to recommend them much anymore. Static class members are perhaps less of a code smell.

In any case, the best path forward is likely a refactor to pass to the Enemy constructor.

Some further reading:

What are drawbacks or disadvantages of singleton pattern?

Why using static namespace/class member variables is a bad idea in C++?

Sign up to request clarification or add additional context in comments.

2 Comments

I haven't been taught singletons nor have I used them but we have covered the static keyword so I think I'll do some reading on that and go for that route. Thanks for providing two solutions as well!
Yep I also think that the best way would be to pass ProjectileManager* to Enemy constructor, this will allow easy unit-testing and still allows to use singleton if you decide it's fine.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.