C++ factory problem

Started by
13 comments, last by sepharion 14 years, 1 month ago
I've got an abstract base class BasicGame which has 2 subclasses AIGame and HumanGame, the type of game used is dependant on commandline arguments at runtime so the main executable has a BasicGame declared as a variable. Obviously I can't instantiate an abstract class so I've got a pointer to the base class. My question is this, how the heck do I convert from the abstract base class pointer into an instance of the subtype (presumably will also have to be a pointer)? I know I could declare an instance of both types, instantiate only 1 of them and only call the methods on the instantiated one but that's clearly a horrible hack.

BasicGame *game;

void createGame(HWND hWnd, HINSTANCE hInstance, LPSTR flags)
{
	RECT screen;
	GetClientRect(hWnd, &screen);
	if(strcmp(flags, "-ai") != 0)
	{
		*game = HumanGame(hInstance, hWnd);
	}
	else
	{
		*game = AIGame(hInstance, hWnd);
	}
}

when I run that I get an error in __vfptr and in all members of the subtype class: CXX0030: Error: expression cannot be evaluated. Cheers, Sepharion
Advertisement
not sure I totally understand your question, but couldn't you just do a cast on your game pointer to either HumanGame or AIGame?
Its all a matter of will power
The cause of the issues is that you are not actually allocating the game object in question. Once you do that you can just use the interface to invoke whichever actions need to be done.

For example:
<code>
game = new HumanGame(hInstance, hWnd);
</code>
Denis Hilliard
oluf - the game is generally set up the same regardless of which type of game so I'm using the base class to do that, later when I read the commandline input it should determine whether it is a HumanGame or an AIGame to add the specific implementation for a couple of methods.

dysfictional - Can it not be done keeping the game on the stack or do I actually need to give it heap space?

I like oluf's idea of casting the BasicGame pointer to a HumanGame or AIGame pointer but I've never really used static casts before and I'm pretty unsure how I would do it on an abstract class.

The example from cplusplus.com
class CBase {};class CDerived: public CBase {};CBase * a = new CBase;CDerived * b = static_cast<CDerived*>(a);


In this case CBase would be BasicGame however because it is abstract it cannot be instantiated.
I think you're confused (and the 'cplusplus.com' example code is also confused). Your original code:
BasicGame *game;*game = HumanGame(hInstance, hWnd);
Takes whatever HumanGame() spits out and does a by-value copy of it into storage that hasn't been allocated yet; most likely slicing it in the process.
To do what you want you can either allocate dynamically (using new), or take pointers to existing (statically allocated) objects. Either of the following functions will give you the pointer you want:-

BasicGame *HumanGame(){   static HumanGameObject obj;   return &obj;}BasicGame *HumanGame(){   return new HumanGameObject();    // preferred}BasicGame *game = HumanGame();


Jans.
Quote:Original post by sepharion
...
I like oluf's idea of casting the BasicGame pointer to a HumanGame or AIGame pointer but I've never really used static casts before and I'm pretty unsure how I would do it on an abstract class.
...


And why would you want to cast BasicGame pointer to HumanGame or AIGame? Can you show some code about it, since it may be unnecessary.

Regards!


use game = new HumanGame(hInstance, hWnd); not *game = HumanGame(hInstance, hWnd);

The example you have shown (from cplusplus.com):

The Base class is not abstract. Classes are abstract there is AT LEAST one pure virtual function inside. And if you want to create a derived class instance do it like that:

Base * child = new Derived;


There is no need of static_cast here. AFAIK static casts are for objects whose types are COMPLETELY different from each other like:

class Base1{};class Base2{};Base1 * base1 = new Base1;Base2 * base2 = static_cast<Base2 *>(base1);


So when you deal with Derived-Base relation use implicit casting, not explicit castings (dynamic_cast, static_cast, reinterpret_cast)
kauna - because updateWorld in HumanGame differs drastically from the functionality in AIGame so is a pure virtual function in BasicGame.

kasya - I meant in my case the base class is abstract because updateWorld() is a pure virtual function. Having read up on casts a dynamic cast will cast from subtype to base type only, static cast can do it either way, reinterpret casts can change it from any 1 thing to any other but is likely to cause crashes at runtime.

jans - Roughly what i've got now which seems to work but has broken other things.

void createInstances(HWND hWnd, HINSTANCE hInstance, LPSTR flags){	RECT screen;	GetClientRect(hWnd, &screen);	if(strcmp(flags, "-ai") != 0)	{		game = new Game(hInstance, hWnd);	}	else	{		game = new AIGame(hInstance, hWnd);	}		}


seems to be doing the trick, although something that I've noticed now is that my animation has broken (and I think it has something to do with this). Every time the control loop inside my updateWorld() method is called it skips a method call. For simplicities sake if the player holds the right arrow key walkRight() is called inside the base class. walkRight() does checks to make sure the player isn't against a wall and should handle which frame of animation is displayed, however something is preventing this method from being called.

void BasicGame::walkRight(){	if(!player.goingRight())	{		player.setGoingRight(true);		player.setFrameNumber(0);		startDirTime = timeGetTime(); // startDirTime defined as a DWORD	}	else	{		DWORD timeInDir = timeGetTime() - startDirTime;		if(timeInDir > 100)		{			nextWalkFrame(); //debugger gets here but never enters method						startDirTime = timeGetTime();		}	}	if(!collision('l'))	{		player.walkLeft();		}}void BasicGame::nextWalkFrame(){	player.setFrameNumber(player.getFrameNumber() +1);	if(player.getFrameNumber() > 8) // 8 frames of walking animation	{		player.setFrameNumber(0);	}}


Any idea why this is being optimised out or is there a way to turn optimisation off?

Cheers,
Sepharion
Quote:Original post by sepharion
because updateWorld in HumanGame differs drastically from the functionality in AIGame so is a pure virtual function in BasicGame.


class BasicGame{ virtual void UpdateWorld() = 0;}void AIGame::UpdateWorld(){  //implement the AIGame version of update world}void HumanGame::UpdateWorld(){  //implement the HumanGame version of update world}//inside your game loopgame->UpdateWorld(); <- this will call the correct updateworld.


Well you still didn't present the case which absolutely requires you to dig up the original type of the BasicGame class. Inheritance is good with dealing such situations where the class implementations differ from each others.

Best regards!
Quote:Any idea why this is being optimised out or is there a way to turn optimisation off?


I am sure a compiler will NEVER optimize a program by omitting a function call that actually does something, and certainly not in debug mode. Are you sure you are using the debugger right? Are you stepping INTO the function (F11 in the VS Debugger) and not just over it?

Have you tried setting a breakpoint within nextWalkFrame() ?

This topic is closed to new replies.

Advertisement