0

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
Andrew WC Brown
  • 2,240
  • 5
  • 22
  • 24
  • 2
    I'm not sure I understand. `Abstract` is completely unrelated to any of your other types. What are you hoping this code would do? – Oliver Charlesworth Jan 01 '15 at 20:56
  • 1
    You declare `engine` as an external `Abstract` and then define it as a `MyGame` which is a `Base` but *not* an `Abstract`. – Galik Jan 01 '15 at 20:57
  • 4
    (Tangent: I propose you remove all the namespacing, as I'm not sure it affects your question, and only serves to add verbosity to your example code...) – Oliver Charlesworth Jan 01 '15 at 20:58
  • I thought if I had my Engine extend from Abstract and Abstract was declared before the extern that I might be able to use initialize my game and it would work since its grandparent is Abstract. I am trying to apply what works in Ruby but obviously it doesn't translate over. Either way I am unsure the best approach to get the result I want. – Andrew WC Brown Jan 01 '15 at 21:05
  • 1
    But none of your classes extend from `Abstract`. (And note that `Engine` is a namespace in your code, not a class...) – Oliver Charlesworth Jan 01 '15 at 21:06
  • mistype on my part. added now – Andrew WC Brown Jan 01 '15 at 21:09
  • sounds like you want to use the Singleton pattern in C++ http://stackoverflow.com/questions/1008019/c-singleton-design-pattern or perhaps this one http://stackoverflow.com/questions/86582/singleton-how-should-it-be-used – Richard Chambers Jan 01 '15 at 21:09
  • It seems your entire problem is that you are defining the relevant functions in the class definition: simply just declare them, after the class definition declare you `extern` object, and then define the corresponding methods! (note, however, that global objects normally end up being a problem and I'm certainly not encouraging you to go that direction, merely pointing out how to solve the problem). – Dietmar Kühl Jan 01 '15 at 21:13
  • [OT]: memory leak for `actors` and `player`. – Jarod42 Jan 01 '15 at 22:59
  • Your instincts are correct, you just don't know how to write it in c++. Is my code what you wanted? In retrospect, I think you should have MyGame create the player (you don't need a global pointer when you already have "this") thus getting rid of new/delete Player. – Kenny Ostrom Jan 03 '15 at 15:18

1 Answers1

0

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;
}
Kenny Ostrom
  • 5,639
  • 2
  • 21
  • 30