Search code examples
c++inheritanceextern

Using extern for a class instance in C++


I want to have a global instance of my engine class so that I may implicitly add actors to my actor managers when an instance of an actor is created. For simplicity I have boiled down all my code into a single file.

My trouble is using extern since how I can use extern when I have not yet define my class. I thought maybe c++ would allow me to use a parent as the type but no luck.

#include <iostream>

namespace Engine { class Abstract {};};
extern Engine::Abstract *engine;

namespace Engine { class Actor {
public:
  Actor(){
    engine->actors->add(this);
  }
};};

namespace Engine { class ActorManager {
public:
  void add(){
    std::cout << "Actor.." << std::endl;
  }
};};

namespace Engine { class Base : Abstract {
public:
  ActorManager *actors;
  void run() {
    actors = new ActorManager();
    this->setup();
  }
  virtual void setup(){}
};};


class Player : Engine::Actor {};

class MyGame : public Engine::Base {
  void setup(){
    Player *player;
    player = new Player();
  }
};

MyGame *engine = new MyGame;
int main(int argc, const char ** argv)
{
  engine->run();
  delete engine;
  return 0;
}

This is how I would achieve this in ruby

$game = nil

module Engine
  class Actor
    def initialize
      $game.actors.add
    end
  end

  class ActorManager
    def add
      puts 'adding an actor'
    end
  end

  class Base
    attr_accessor :actors
    def initialize
      self.actors = ActorManager.new
    end
  end
end

class Player < Engine::Actor
end

class Game < Engine::Base
  def run
    Player.new
  end
end

$game = Game.new
$game.run

Solution

  • header only for most of the base classes so it compiles but will not link (as you know)

    namespace Engine {
        // header info only - nothing is defined here
    
        class Actor {
        }; 
    
        // interface for ActorManager
        class ActorManager {
        public:
            void add(const Actor*);
        };
        extern ActorManager * global_pManager;
    
        // interface for Game
        class Game : public ActorManager {
        public:
            virtual ~Game(){};         // you need a virtual destructor
            virtual void setup() = 0;  // abstract interface
            virtual void run() = 0;    // abstract interface
        };
    };
    
    // header for your game and player logic
    class Player : public Engine::Actor {
    };
    class MyGame : public Engine::Game {
    public:
        void setup();
        void run();
    };
    
    int main(int argc, const char ** argv)
    {
        // scope of main is a better way to control the lifetime of this object
        MyGame engine;        
    
        // here's the global pointer you requested
        Engine::global_pManager = static_cast<Engine::ActorManager*>(&engine);
    
        engine.run();
        return 0;
    }