Page 1 of 1

Extending a class with pure virtual functions

Posted: Mon Aug 16, 2010 11:21 am
by ajtgarber
My compiler is bitching about not being able to allocate an instance of MyGame because some of its methods are pure virtual, I've given the methods definitions in the subclass but it doesn't seem to care.

Game.h

Code: Select all

#pragma once

#include <SDL/SDL.h>
#include <SDL/SDL_opengl.h>

//Abstract class
class Game {
private:
	int requestedFPS;
	int reportedFPS;
	SDL_Surface* screen;
	int width;
	int height;
	
public:
	Game(int width, int height);
	virtual ~Game();
	
	virtual void update() const = 0;
	virtual void render() const = 0;
	virtual void init() const = 0;
	
	virtual void keyEvent(int event, int key) const = 0;
	virtual void mouseEvent(int event, int x, int y, int button) const = 0;
	
	int getRequestedFPS();
	int getReportedFPS();
	
	void setRequestedFPS(int requestedFPS);
	void setReportedFPS(int reportedFPS);
	
	int getWidth();
	int getHeight();
};
MyGame.h

Code: Select all

#pragma once

#include "Game.h"

class MyGame : public Game {
public:
	MyGame(int width, int height);
	
	virtual void init();
	virtual void update();
	virtual void render();
	
	virtual void keyEvent(int event, int key);
	virtual void mouseEvent(int event, int x, int y, int button);
};
main.cpp

Code: Select all

#include <iostream>
#include <SDL/SDL.h>
#include <SDL/SDL_opengl.h>

#include "FBEngine.h"
#include "Game.h"
#include "MyGame.h"

using namespace std;

int main(int argc, char* argv[]) {
	MyGame *game = new MyGame(640, 480);
	FBEngine *engine = FBEngine::getInstance();
	engine->setGame(game);
	engine->start();
	
	delete game;
	return 0;
}

Re: Extending a class with pure virtual functions

Posted: Mon Aug 16, 2010 11:29 am
by Ginto8
I'd need to see the FBengine class (more specifically the setGame method) and the exact error message before I can give you an answer. From the code given, it seems perfectly fine.

Re: Extending a class with pure virtual functions

Posted: Mon Aug 16, 2010 11:38 am
by ajtgarber
FBEngine.h

Code: Select all

#pragma once

#include <SDL/SDL_opengl.h>
#include <SDL/SDL.h>
#include <ctime>

#include "Game.h"

#define FBE_MOUSE_MOVED 0
#define FBE_MOUSE_PRESSED 1
#define FBE_MOUSE_RELEASED 2

#define FBE_KEY_PRESSED 0
#define FBE_KEY_RELEASED 1

class FBEngine {
private:
	Game* game;
	bool running;
	
public:
	static inline FBEngine* getInstance() {
		static FBEngine* instance;
		if(instance == NULL) {
			instance = new FBEngine();
		}
		return instance;
	}
	
	FBEngine();
	virtual ~FBEngine();
	
	void setGame(Game* game);
	Game* getGame();
	
	bool isRunning();
	void setRunning(bool running);
	
	void start();
};
FBEngine.cpp

Code: Select all

/*
 *  FBEngine.cpp
 *  SDLOpenGLTest
 *
 *  Created by Ajtgarber on 8/15/10.
 *  Copyright 2010 __MyCompanyName__. All rights reserved.
 *
 */

#include "FBEngine.h"

FBEngine::FBEngine() : running(false) {

}

FBEngine::~FBEngine() {

}

void FBEngine::setGame(Game* game) {
	this->game = game;
}
Game* FBEngine::getGame() {
	return game;
}

bool FBEngine::isRunning() {
	return running;
}
void FBEngine::setRunning(bool running) {
	this->running = running;
}

void FBEngine::start() {
	if(game == NULL) {
		return;
	}
	running = true;
	
	while(running) {
		int startTime = time(0);
		SDL_Event event;
		while(SDL_PollEvent(&event)) {
			if(event.type == SDL_QUIT) {
				running = false;
				break;
			} else if(event.type == SDL_KEYUP) {
				game->keyEvent(FBE_KEY_RELEASED, event.key.keysym.sym);
			} else if(event.type == SDL_KEYDOWN) {
				game->keyEvent(FBE_KEY_PRESSED, event.key.keysym.sym);
			} else if(event.type == SDL_MOUSEMOTION) {
				int x = event.motion.x;
				int y = event.motion.y;
				game->mouseEvent(FBE_MOUSE_MOVED, x, y, event.button.button);
			} else if(event.type == SDL_MOUSEBUTTONUP) {
				int x = event.motion.x;
				int y = event.motion.y;
				game->mouseEvent(FBE_MOUSE_RELEASED, x, y, event.button.button);
			} else if(event.type == SDL_MOUSEBUTTONDOWN) {
				int x = event.motion.x;
				int y = event.motion.y;
				game->mouseEvent(FBE_MOUSE_PRESSED, x, y, event.button.button);
			}
		}
		game->update();
		game->render();
		glFlush();
		SDL_GL_SwapBuffers();
		int newTime = time(0);
		int timeTaken = newTime-startTime;
		if(timeTaken > game->getRequestedFPS()) {
			SDL_Delay(5);
		} else {
			SDL_Delay((game->getRequestedFPS()) - timeTaken);
		}
		
		game->setReportedFPS((timeTaken/1000));
	}
}
Error:

Code: Select all

CompileC build/SDLOpenGLTest.build/Debug/SDLOpenGLTest.build/Objects-normal/i386/main.o main.cpp normal i386 c++ com.apple.compilers.gcc.4_0
cd /Users/jacobgarber/Desktop/SDLOpenGLTest
setenv LANG en_US.US-ASCII
/Developer/usr/bin/gcc-4.0 -x c++ -arch i386 -fmessage-length=0 -pipe -Wno-trigraphs -fpascal-strings -fasm-blocks -O0 -Wreturn-type -Wunused-variable -isysroot /Developer/SDKs/MacOSX10.5.sdk -mfix-and-continue -fvisibility-inlines-hidden -mmacosx-version-min=10.5 -gdwarf-2 -I/Users/jacobgarber/Desktop/SDLOpenGLTest/build/SDLOpenGLTest.build/Debug/SDLOpenGLTest.build/SDLOpenGLTest.hmap -F/Users/jacobgarber/Desktop/SDLOpenGLTest/build/Debug -F/Users/jacobgarber/Library/Frameworks -F/Developer/SDKs/MacOSX10.5.sdk/Library/Frameworks -I/Users/jacobgarber/Desktop/SDLOpenGLTest/build/Debug/include -I/Users/jacobgarber/Library/Frameworks/SDL.framework/Headers -I/Developer/SDKs/MacOSX10.5.sdk/Library/Frameworks/SDL.framework/Headers -I/Users/jacobgarber/Desktop/SDLOpenGLTest/build/SDLOpenGLTest.build/Debug/SDLOpenGLTest.build/DerivedSources/i386 -I/Users/jacobgarber/Desktop/SDLOpenGLTest/build/SDLOpenGLTest.build/Debug/SDLOpenGLTest.build/DerivedSources -include /var/folders/RI/RIxlp3ksGAWi66A-rj783E+++TI/-Caches-/com.apple.Xcode.501/SharedPrecompiledHeaders/SDLOpenGLTest_Prefix-eenihgompdfifncobrlrsehetnkm/SDLOpenGLTest_Prefix.pch -c /Users/jacobgarber/Desktop/SDLOpenGLTest/main.cpp -o /Users/jacobgarber/Desktop/SDLOpenGLTest/build/SDLOpenGLTest.build/Debug/SDLOpenGLTest.build/Objects-normal/i386/main.o

/Users/jacobgarber/Desktop/SDLOpenGLTest/main.cpp: In function 'int SDL_main(int, char**)':
/Users/jacobgarber/Desktop/SDLOpenGLTest/main.cpp:12: error: cannot allocate an object of abstract type 'MyGame'
/Users/jacobgarber/Desktop/SDLOpenGLTest/MyGame.h:5: note:   because the following virtual functions are pure within 'MyGame':
/Users/jacobgarber/Desktop/SDLOpenGLTest/Game.h:19: note:  virtual void Game::update() const
/Users/jacobgarber/Desktop/SDLOpenGLTest/Game.h:20: note:  virtual void Game::render() const
/Users/jacobgarber/Desktop/SDLOpenGLTest/Game.h:21: note:  virtual void Game::init() const
/Users/jacobgarber/Desktop/SDLOpenGLTest/Game.h:23: note:  virtual void Game::keyEvent(int, int) const
/Users/jacobgarber/Desktop/SDLOpenGLTest/Game.h:24: note:  virtual void Game::mouseEvent(int, int, int, int) const

CompileC build/SDLOpenGLTest.build/Debug/SDLOpenGLTest.build/Objects-normal/ppc/main.o main.cpp normal ppc c++ com.apple.compilers.gcc.4_0
cd /Users/jacobgarber/Desktop/SDLOpenGLTest
setenv LANG en_US.US-ASCII
/Developer/usr/bin/gcc-4.0 -x c++ -arch ppc -fmessage-length=0 -pipe -Wno-trigraphs -fpascal-strings -fasm-blocks -O0 -Wreturn-type -Wunused-variable -isysroot /Developer/SDKs/MacOSX10.5.sdk -mfix-and-continue -mtune=G5 -fvisibility-inlines-hidden -mmacosx-version-min=10.5 -gdwarf-2 -I/Users/jacobgarber/Desktop/SDLOpenGLTest/build/SDLOpenGLTest.build/Debug/SDLOpenGLTest.build/SDLOpenGLTest.hmap -F/Users/jacobgarber/Desktop/SDLOpenGLTest/build/Debug -F/Users/jacobgarber/Library/Frameworks -F/Developer/SDKs/MacOSX10.5.sdk/Library/Frameworks -I/Users/jacobgarber/Desktop/SDLOpenGLTest/build/Debug/include -I/Users/jacobgarber/Library/Frameworks/SDL.framework/Headers -I/Developer/SDKs/MacOSX10.5.sdk/Library/Frameworks/SDL.framework/Headers -I/Users/jacobgarber/Desktop/SDLOpenGLTest/build/SDLOpenGLTest.build/Debug/SDLOpenGLTest.build/DerivedSources/ppc -I/Users/jacobgarber/Desktop/SDLOpenGLTest/build/SDLOpenGLTest.build/Debug/SDLOpenGLTest.build/DerivedSources -include /var/folders/RI/RIxlp3ksGAWi66A-rj783E+++TI/-Caches-/com.apple.Xcode.501/SharedPrecompiledHeaders/SDLOpenGLTest_Prefix-drfvvyxxhgcgicabnlgfhedlivxo/SDLOpenGLTest_Prefix.pch -c /Users/jacobgarber/Desktop/SDLOpenGLTest/main.cpp -o /Users/jacobgarber/Desktop/SDLOpenGLTest/build/SDLOpenGLTest.build/Debug/SDLOpenGLTest.build/Objects-normal/ppc/main.o

/Users/jacobgarber/Desktop/SDLOpenGLTest/main.cpp: In function 'int SDL_main(int, char**)':
/Users/jacobgarber/Desktop/SDLOpenGLTest/main.cpp:12: error: cannot allocate an object of abstract type 'MyGame'
/Users/jacobgarber/Desktop/SDLOpenGLTest/MyGame.h:5: note:   because the following virtual functions are pure within 'MyGame':
/Users/jacobgarber/Desktop/SDLOpenGLTest/Game.h:19: note:  virtual void Game::update() const
/Users/jacobgarber/Desktop/SDLOpenGLTest/Game.h:20: note:  virtual void Game::render() const
/Users/jacobgarber/Desktop/SDLOpenGLTest/Game.h:21: note:  virtual void Game::init() const
/Users/jacobgarber/Desktop/SDLOpenGLTest/Game.h:23: note:  virtual void Game::keyEvent(int, int) const
/Users/jacobgarber/Desktop/SDLOpenGLTest/Game.h:24: note:  virtual void Game::mouseEvent(int, int, int, int) const

Re: Extending a class with pure virtual functions

Posted: Mon Aug 16, 2010 11:39 am
by qpHalcy0n
You can not instantiate a pure virtual class object. This is called an abstract class or "interface".

They can not be instantiated.

Re: Extending a class with pure virtual functions

Posted: Mon Aug 16, 2010 11:43 am
by programmerinprogress
You can only use pointers to an abstract class, with memory allocated to a derived class e.g.

Base* pBase = new Derived();

This is one method of polymorphism in C++.

just thought I would elaborate further on the previous (you cant't instantiate abstract classes)

Re: Extending a class with pure virtual functions

Posted: Mon Aug 16, 2010 12:32 pm
by ajtgarber
I know this, but how do I get MyGame to not be an abstract class?

Re: Extending a class with pure virtual functions

Posted: Mon Aug 16, 2010 12:35 pm
by Ginto8
ok the fix was easy:

Code: Select all

#pragma once

#include "Game.h"

class MyGame : public Game {
public:
   MyGame(int width, int height);
   
   virtual void init() const;
   virtual void update() const;
   virtual void render() const;
   
   virtual void keyEvent(int event, int key) const;
   virtual void mouseEvent(int event, int x, int y, int button) const;
};
the error was caused because the implementations you defined were not const, so it thought you still had more things to define.

Re: Extending a class with pure virtual functions

Posted: Mon Aug 16, 2010 2:05 pm
by programmerinprogress
ajtgarber wrote:I know this, but how do I get MyGame to not be an abstract class?
Simple answer without looking at the code, derive a new class and implement all of the methods that you haven't defined (the ones you declared as =0).

Re: Extending a class with pure virtual functions

Posted: Mon Aug 16, 2010 5:18 pm
by ajtgarber
Thanks for all the help guys :) , now its giving me another error :P. I'm not really sure why though... sorry I'm not quite used to the C++ compiler messages yet

Code: Select all

/Users/jacobgarber/Desktop/SDLOpenGLTest/MyGame.cpp:19:0 /Users/jacobgarber/Desktop/SDLOpenGLTest/MyGame.cpp:19: error: passing 'const MyGame' as 'this' argument of 'int Game::getWidth()' discards qualifiers


/Users/jacobgarber/Desktop/SDLOpenGLTest/MyGame.cpp:19:0 /Users/jacobgarber/Desktop/SDLOpenGLTest/MyGame.cpp:19: error: passing 'const MyGame' as 'this' argument of 'int Game::getHeight()' discards qualifiers


/Users/jacobgarber/Desktop/SDLOpenGLTest/MyGame.cpp:19:0 /Users/jacobgarber/Desktop/SDLOpenGLTest/MyGame.cpp:19: error: passing 'const MyGame' as 'this' argument of 'int Game::getWidth()' discards qualifiers


/Users/jacobgarber/Desktop/SDLOpenGLTest/MyGame.cpp:19:0 /Users/jacobgarber/Desktop/SDLOpenGLTest/MyGame.cpp:19: error: passing 'const MyGame' as 'this' argument of 'int Game::getHeight()' discards qualifiers
Code its pointing to (MyGame init function):

Code: Select all

void MyGame::init() const {
	SDL_WM_SetCaption("Test SDL/OpenGL", NULL);
	
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0, this->getWidth(), this->getHeight(), 0, -1, 1);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

Re: Extending a class with pure virtual functions

Posted: Mon Aug 16, 2010 5:47 pm
by Ginto8
well maybe you should, instead of adding const's to your MyGame class, remove the const's from the Game abstract class. That would probably be the better strategy.

Re: Extending a class with pure virtual functions

Posted: Mon Aug 16, 2010 7:28 pm
by ajtgarber
Thanks :D, what exactly does the const after the function header actually mean? I remember reading somewhere that a function with const after it can't call another function that doesn't have it.

P.S Ginto8 nice signature

Re: Extending a class with pure virtual functions

Posted: Mon Aug 16, 2010 8:31 pm
by Ginto8
ajtgarber wrote:Thanks :D, what exactly does the const after the function header actually mean? I remember reading somewhere that a function with const after it can't call another function that doesn't have it.
A function with const after it cannot modify any data of the class. This is so that the compiler can tell if a method can be used safely by a const instance of the class, because if a function tries to modify const data, it won't work exactly the way you want it to. ;)
ajtgarber wrote:P.S Ginto8 nice signature
:mrgreen: