C++ Derived Class problems - c++

I am making a game in C++ and am having problems with my derived class. I have a base class called GameScreen which has a vitrual void draw() function with no statements. I also have a derived class called MenuScreen which also has a virtual void draw() function and a derived class from MenuScreen called TestMenu which also has a void draw() function. In my program I have a list of GameScreens that I have a GameScreen iterator pass through calling each GameScreens draw() function.
The issue is that I have placed a TestMenu object on the GameScreen list. Instead of the iterator calling the draw() function of TestMenu it is calling the draw() function of the GameScreen class. Does anyone know how I could call the draw() function of TestMenu instead of the one in GameScreen.
Here is the function:
// Tell each screen to draw itself.
//gsElement is a GameScreen iterator
//gsScreens is a list of type GameScreen
void Draw()
{
for (gsElement = gsScreens.begin(); gsElement != gsScreens.end(); gsElement++)
{
/*if (gsElement->ssState == Hidden)
continue;*/
gsElement->Draw();
}
}
Here are a copy of my classes:
class GameScreen {
public:
string strName;
bool bIsPopup;
bool bOtherScreenHasFocus;
ScreenState ssState;
//ScreenManager smScreenManager;
GameScreen(string strName){
this->strName = strName;
}
//Determine if the screen should be drawn or not
bool IsActive(){
return !bOtherScreenHasFocus &&
(ssState == Active);
}
//------------------------------------
//Load graphics content for the screen
//------------------------------------
virtual void LoadContent(){
}
//------------------------------------
//Unload content for the screen
//------------------------------------
virtual void UnloadContent(){
}
//-------------------------------------------------------------------------
//Update changes whether the screen should be updated or not and sets
//whether the screen should be drawn or not.
//
//Input:
// bOtherScreenHasFocus - is used set whether the screen should update
// bCoveredByOtherScreen - is used to set whether the screen is drawn or not
//-------------------------------------------------------------------------
virtual void Update(bool bOtherScreenHasFocus, bool bCoveredByOtherScreen){
this->bOtherScreenHasFocus = bOtherScreenHasFocus;
//if the screen is covered by another than change the screen state to hidden
//else set the screen state to active
if(bCoveredByOtherScreen){
ssState = Hidden;
}
else{
ssState = Active;
}
}
//-----------------------------------------------------------
//Takes input from the mouse and calls appropriate actions
//-----------------------------------------------------------
virtual void HandleInput(){
}
//----------------------
//Draw content on screen
//----------------------
virtual void Draw(){
}
//--------------------------------------
//Deletes screen from the screen manager
//--------------------------------------
void ExitScreen(){
//smScreenManager.RemoveScreen(*this);
}
};
class MenuScreen: public GameScreen{
public:
vector <BUTTON> vbtnMenuEntries;
MenuScreen(string strName):GameScreen(strName){
}
virtual void Update(bool bOtherScreenHasFocus, bool bCoveredByOtherScreen){
GameScreen::Update(bOtherScreenHasFocus, bCoveredByOtherScreen);
for(unsigned int i = 0; i < vbtnMenuEntries.size(); i++){
vbtnMenuEntries[i].IsPressed();
}
}
virtual void Draw(){
GameScreen::Draw();
for(unsigned int i = 0; i < vbtnMenuEntries.size(); i++)
vbtnMenuEntries[i].Draw();
}
};
class testMenu : public MenuScreen{
public:
vector<OBJECT> test;
//OBJECT background3();
// OBJECT testPic(512, 384, buttonHover.png, 100, 40, 100, 40);
// BUTTON x(256, 384, buttonNormal.png, buttonHover.png, buttonPressed.png, 100, 40, test());
bool draw;
testMenu():MenuScreen("testMenu"){
OBJECT background3(1, 1, 0, TEXT("background.png"), 1, 1, 1024, 768);
OBJECT testPic(512, 384,0, TEXT("buttonHover.png"), 1, 1, 100, 40);
test.push_back(background3);
test.push_back(testPic);
//background3.Init(int xLoc, int yLoc, int zLoc, LPCTSTR filePath, int Rows, int Cols, int Width, int Height)
//test.push_back(background3);
// vbtnMenuEntries.push_back(x);
draw = false;
}
void Update(bool bOtherScreenHasFocus, bool bCoveredByOtherScreen){
MenuScreen::Update(bOtherScreenHasFocus, bCoveredByOtherScreen);
//cout << "X" << endl;
/*if(MouseLButton == true){
testMenu2 t;
smManager.AddScreen(t);
}*/
}
void Draw(){
//background3.Draw();
test[0].Draw();
test[1].Draw();
MenuScreen::Draw();
///*if(draw){*/
// testPic.Draw();
//}
}
/*void test(){
draw = true;
}*/
};

If gsScreens is a list of objects instead of a list of pointers (as your code suggests), then you're not storing what you think you're storing in it.
What's happening is that -- instead of putting a TestMenu into the list, you're actually constructing a new MenuScreen using the compiler-generated copy constructor and putting this MenuScreen into the list.
C++ is polymorphic through pointers, so if you don't have a pointer you won't get polymorphic behavior.

To get the polymorphic behavior you're after and at the same time use a std::vector<>, you must store pointers to the base class type in the vector, instead of storing values. Also, you must remember to free their memory before the vector goes out of scope.
For instance:
#include <vector>
#include <algorithm>
struct Base
{
virtual void Foo() = 0;
virtual ~Base() { }
};
struct Derived1 : public Base
{
void Foo() { }
};
struct Derived2 : public Base
{
void Foo() { }
};
struct delete_ptr
{
template <typename T>
void operator()(T& p)
{
delete p;
p = 0;
}
};
int wmain(int, wchar_t*[])
{
std::vector<Base*> items;
items.push_back(new Derived1);
items.push_back(new Derived2);
Base& first = items.front();
first.Foo(); // Will boil down to Derived1::Foo().
Base& last = items.back();
last.Foo(); // Will boil down to Derived2::Foo().
std::for_each(items.begin(), items.end(), delete_ptr())
};

Curt is absolutely correct, but I'd just like to throw a little more information at it.
This problem (storing base-class objects, rather than pointers) is sometimes called "slicing".
Also, I tend to make use of the following macro:
#define DISALLOW_COPYING(X) \
private: \
X(const X &); \
const X& operator= (const X& x)
Then you put this somewhere in your class definition:
class Foo {
// ...
DISALLOW_COPYING(Foo);
};
If another class attempts to copy the object, you'll get a compiler error (because the methods are declared private). If the class itself attempts to copy the object, you'll get a linker error (because the methods have no implementation).

Boost (www.boost.org, a library I would recommend anyone coding in C++ use) provides a noncopyable base class that does exactly that; you don't need an ugly macro that way.

Related

c++ Inheritance and shared pointers

Here is the situation. Let's say we have a virtual base class (e.g. ShapeJuggler) which contains a method that takes a shared pointer to a virtual base class object (e.g. Shape) as argument. Let's jump into the following pseudo-code to understand:
class Shape {
}
class ShapeJuggler {
virtual void juggle(shared_ptr<Shape>) = 0;
}
// Now deriving a class from it
class Square : public Shape {
}
class SquareJuggler : public ShapeJuggler {
public:
void juggle(shared_ptr<Shape>) {
// Want to do something specific with a 'Square'
// Or transform the 'shared_ptr<Shape>' into a 'shared_ptr<Square>'
}
}
// Calling the juggle method
void main(void) {
shared_ptr<Square> square_ptr = (shared_ptr<Square>) new Square();
SquareJuggler squareJuggler;
squareJuggler.juggle(square_ptr); // how to access 'Square'-specific members?
}
make_shared or dynamic/static_cast don't seem to do the job.
Is it at all possible? Any ideas, suggestions?
Thanks
This is where std::dynamic_pointer_cast (or one of its friends) comes into play.
It's just like dynamic_cast, but for std::shared_ptrs.
In your case (assuming the Shape class is polymorphic so dynamic_cast works):
void juggle(shared_ptr<Shape> shape) {
auto const sq = std::dynamic_pointer_cast<Square>(shape);
assert(sq);
sq->squareSpecificStuff();
}
This is the multiple dispatch problem. Their are many solution to this problem, the cleanest might be using the visitor pattern, but if you just have one function that need multiple dispatch you could avoid using a visitor:
class SquareJuggler;
class TriangleJuggler;
//.... others concrete jugglers.
class Shape {
//The default behaviour for any juggler and any shape
virtual void juggle_by(Juggler& t) {
//default code for any shape an juggle
}
// list each juggler for which you may
// implement a specific behavior
virtual void juggle_by(SquareJuggler& t) {
//provides default behavior in case you will not
// create a specific behavior for a specific shape.
//for example, just call the unspecific juggler:
this->Shape::juggle_by(static_cast<Juggler&>(t));
}
virtual void juggle_by(TriangleJuggler& t) {
//provides default behavior in case you will not
//create a specific behavior for a specific shape.
//for example, just call the unspecific juggler:
this->Shape::juggle_by(static_cast<Juggler&>(t));
}
//...
};
// Now deriving a class from it
class Square : public Shape {
void juggle_by(SquareJuggler& s) override{
//code specific to SquareJuggler and Shape
}
};
class Triangle : public Shape {
void juggle_by(TriangleJuggler& t) override{
//code specific to TriangleJuggler and Shape
}
};
class ShapeJuggler {
virtual void juggle(shared_ptr<Shape> s) {
//by default (if default has sense):
s->juggle_by(*this);
}
};
class SquareJuggler: public ShapeJuggler {
public:
void juggle(shared_ptr<Shape> s) override {
s->juggle_by(*this);
}
};
class TriangleJuggler: public ShapeJuggler {
public:
void juggle(shared_ptr<Shape> s) override {
s->juggle_by(*this);
}
};
// Calling the juggle method
void main(void) {
shared_ptr<Square> square_ptr = (shared_ptr<Square>) new Square();
SquareJuggler squareJuggler;
squareJuggler.juggle(square_ptr);
//This last call, will perform two virtual calls:
// 1. SquareJuggler::juggle(shared_ptr<Shape);
// 2. Square::juggle_by(SquareJuggler&);
}
You could also defines your XXXJuggler as final, which will enable some devirtualization optimization.

C++ calling method of subclass in superclass?

I have an EnemyBullet subclass of superclass Bullet.
Now I'm calling the Bullet method Process() using an EnemyBullet object.
What I want is to determine whether the current object is an EnemyBullet to distinguish from Bullet action.
My code is like this,
void Bullet::Process(float deltaTime)
{
// Generic position update, based upon velocity (and time).
m_y = m_y + this->GetVerticalVelocity()*deltaTime;
m_pSprite->SetY(static_cast<int>(m_y));
m_pSprite->SetX(static_cast<int>(m_x));
if (m_y < 0)
{
SetDead(true);
}
//Here I want to detect current object is an EnemyBullet, then define a different action
//I tried the following code, but it didn't work
if (EnemyBullet* v = static_cast<EnemyBullet*>(Bullet)) {
if (m_y >800)
{
SetDead(true);
}
}
}
Here's an example of calling a method on an instance of a subclass from a method in the superclass:
class Bullet {
public:
void process() {
// update m_y...
// update sprite position...
if (this->isDead()) {
// handle dead bullet...
}
}
virtual bool isDead() {
return (m_y < 0);
}
protected:
int m_y;
};
class EnemyBullet : public Bullet {
public:
bool isDead() override {
return (m_y > 800);
}
};
Note how each bullet type has custom isDead logic.

Polymorphism with new data members

I would like to write a function that can initialize and return objects of different classes using polymorphism. I also would like these classes to have different data members which may be called through the virtual function. What I wrote below might work. Could you check if I have some undefined behavior in there? Thank you! One thing I am worried about is that when I call "delete polypoint" at the end it will not free the data member "scale" that is unique to "CRectangle". If my code doesn't work is there a way to make it work?
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area ()
{ return (0); }
};
class CRectangle: public CPolygon {
public:
int scale;
int area ()
{ return (width * height * scale ); }
};
CPolygon *polytestinner()
{
CPolygon *polypoint = 0;
int consoleinput = 2;
if (consoleinput>1)
{
CRectangle *rectpoint = new CRectangle();
rectpoint->scale = 4;
polypoint = rectpoint;
}
polypoint->set_values(3,4);
return polypoint;
}
void polytest()
{
CPolygon *polypoint = polytestinner();
gstd::print<int>(polypoint->area());
delete polypoint;
}
int main()
{
polytest();
return 0;
}
Thank you!
I feel compelled to point out Andrei Alexandrescu's object factory architecture. It allows your architecture to grow without having to modify the factory every time you create a concrete type. It is based on a "callback register", and it is actually implemented as a generic component in some libraries. The code is below.
Live Code Example
#include<map>
#include<iostream>
#include<stdexcept>
// your typical base class
class Shape {
public:
virtual void Draw() const = 0;
// virtual destructor allows concrete types to implement their own
// destrucion mechanisms
virtual ~Shape() {}
};
// this factory architecture was suggested by Andrei Alexandrescu in
// his book "Modern C++ Design" --- read it to get the full
// explanation (and a more generic implementation); this is just an
// example
class ShapeFactory {
public:
// this typedef allows to "name" arbitrary functions which take no
// arguments and return a pointer to a Shape instance
typedef Shape* (*CreateShapeCallback)();
Shape* CreateShape(int ShapeId) {
// try to find the callback corresponding to the given shape id;
// if no shape id found, throw exception
CallbackMap::const_iterator it = m_callbacks.find(ShapeId);
if(it == m_callbacks.end()) {
throw std::runtime_error("unknown shape id");
} else {
// create the instance using the creator callback
return (it->second)();
}
}
bool RegisterShape(int ShapeId, CreateShapeCallback Creator) {
// returns true if shape was registered; false if it had already
// been registered
return m_callbacks.insert(CallbackMap::value_type(ShapeId, Creator)).second;
}
bool UnRegisterShape(int ShapeId) {
// returns true if shape was unregistered, false if it was not
// registered in the first place
return m_callbacks.erase(ShapeId) == 1;
}
private:
// the typedef simplifies the implementation
typedef std::map<int, CreateShapeCallback> CallbackMap;
// the callbacks are stored in a map int->callback (see typedef
// above)
CallbackMap m_callbacks;
};
// create some concrete shapes... you would do this in other CPP files
class Line : public Shape {
public:
void Draw() const {
std::cout<<"Drawing a line"<<std::endl;
}
};
// another concrete shape...
class Circle : public Shape {
public:
void Draw() const {
std::cout<<"Drawing a circle"<<std::endl;
}
};
// ... other concrete shapes...
enum ShapeIds {LINE=1, CIRCLE, COUNT};
Shape* CreateLine() { return new Line; }
Shape* CreateCircle() { return new Circle; }
int main() {
// suppose this is the "singleton" instance for the ShapeFactory
// (this is an example! Singletons are not implemented like this!)
ShapeFactory *factory = new ShapeFactory;
factory->RegisterShape(ShapeIds::LINE, CreateLine);
factory->RegisterShape(ShapeIds::CIRCLE, CreateCircle);
Shape* s1 = factory->CreateShape(ShapeIds::CIRCLE);
Shape* s2 = factory->CreateShape(ShapeIds::LINE);
s1->Draw();
s2->Draw();
// will throw an error
try {
Shape *s3 = factory->CreateShape(-1);
s3->Draw();
} catch(const std::exception& e) {
std::cout<<"caught exception: "<<e.what()<<std::endl;
}
return 0;
}
CPolygon needs a virtual destructor:
virtual ~CPolygon() {}
You have undefined behavior in your code:
CPolygon *polypoint;
delete polypoint;
deleting a base class pointer when there is no virtual destructor will result in undefined behavior.
Your CPolygon class and CRectangle classes have no destructors, though the compiler will generate default destructor for you in this case, but they are not virtual by default. Therefore, you need to at least define a virtual destructor for your base class, i.e., CPolygon.

GUI and Text Mode C++ design to remove redundancy (optional parameter? function overloading?)

Using C++, I have a text mode and a GUI mode implemented using FLTK chosen by command line option and I see a lot of redundancy in the codes except for an extra parameter in the GUI case which I need to pass in the main window widget. I'm wondering if there are ways to remove the redundancy? Maybe I have some design issue completely wrong? I'd appreciate the help and please let me know if there are additional information needed. I have thought of using optional parameter, but cannot take a NULL reference.
Here're a skeleton of the codes that are really similar (Not exact, but should be close enough to see the general structure). There may be some more if/else loops or functions nested before I have the one different call with the extra Window& parameter, but this is basically the structure, which actually continue a few levels down.
Thanks for any help!
int Game::init(){
if (graphics){
std::unique_ptr<Window> window = std::unique_ptr<Window>(new Window(...))
return Fl::run();
} else {
play_game();
return 0;
}
}
void Window::init(Fl_Widget* w, void *uData){
Window* window = (Window*) uData;
Window->game.play_game(window);
//Window has a private game& that is constructed to be equal to the game above.
}
void Game::play_game(){
while(!over()){
foo();
bar();
}
}
void Game::play_game(Window& window){
while(!over()){
foo();
bar(window);
}
}
void Game::bar(){
if(!a()){
b();
} else {
c();
}
}
void Game::bar(Window& window){
if(!a()){
b();
} else {
c(window);
window.redraw();
}
}
A similar but different question deals with how I deal with the static function in FLTK, I have similar code somewhere that is like this:
void Game::c(){
if(check_this()){
do_this();
}
}
void Game::c(Window& window){
Fl::run();
}
static void Window::call_back(Fl_Widget* w, void* uData){
Window* window = (Window *) uData;
if(window->game.check_this()){
window->do_this();
}
}
Parameter is not the way to go. Subclassing Game is the way to go. Any method that needs access to the window is virtual and overridden appropriately in the window-specific subclass.
class Game // I hate K&R braces, sorry
{
public:
enum GameType { cli, win };
static Game &GameFactory(GameType gt)
{
switch (gt)
{
case cli: return /* ref to instance of CliGame() */;
case win: return /* ref to instance of WinGame() */;
}
}
virtual int launch() = 0;
void foo();
void bar()
{
if (!a()) { b(); } else { c(); }
}
bool a();
void b();
virtual void c();
void play()
{
while (!over()) { foo(); bar(); }
}
private:
// need some sort of static management of instance of game, how is up to you
};
class WinGame : public Game
{
public:
virtual int launch()
{
window = std::unique_ptr<Window>(new Window(...));
return Fl::run(); // presumably calls play_game() sometime....
}
protected:
virtual void c()
{
// does whatever, using window *member* (not argument)
window.redraw();
}
private:
std::unique_ptr<Window> window;
};
class CliGame : public Game
{
virutal int launch()
{
play_game();
return 0;
}
virtual void c()
{
// does whatever
}
};
int main()
{
Game::GameType graphics;
// 'graphics' gets set somehow
Game &g = Game::GameFactory(graphics);
int retval = g.launch();
// etc
}
Can you make window a member of your Game class so that you don't have to pass it around so much?
One way to do this - while still maintaining Game seperate from the windowing - is to use templates. This would involve an interface change, however, and so may not be appropriate.
First of all separate your window specific and console specific code:
//class containing all your window management
class window
{
window()
{
//construct
std::unique_ptr<Window> m_window = std::unique_ptr<Window>(new Window(...));
}
void
redraw()
{
m_window.redraw();
}
private:
std::unique_ptr<Window> m_window;
};
//your console management
class console
{
};
Then load up your game with your windowing/console option.
Inherit from your option so that you can use the domain specific functions.
template<WindowOption>
class Game : public WindowOption
{
void
play_game()
{
while(!over()){
foo();
bar();
}
}
void
bar() //request for window functions deferred
{
if(!a()){
b();
} else {
c();
}
}
void b()
{
//console default
}
void c()
{
//console default
}
};
Then specialize the functions that need to call window specific menthods.
template<>
Game<window>::b()
{
//with window specialisation
//can call window specific functions here as we have a window.
redraw();
}
template<>
Game<window>::c()
{
//with window specialisation
//can call window specific functions here as we have a window.
redraw();
}
Then call:
int
main (int ac, char **av)
{
Game<window> gw;
Game<console> gc;
}

Why is virtual function not being called?

//GUITEXT
class guitext : public entity {
public:
guitext(graphics *gfx, std::string _text, float _x, float _y,
float _size, float timeToLive);
bool update(float deltaTime, gameworld *world);
void draw(graphics *gfx);
};
void guitext::draw(graphics *gfx) { printf("draw"); }
//ENTITY
class entity {
public:
virtual bool update(float deltaTime, gameworld *world)
{ return false; }
virtual void draw(graphics *gfx) { }
};
//GAMEWORLD
void gameworld::addEntity(entity e) { entitys.push_back(e); }
//MAIN
for(int i = 0; i < (int)entitys.size(); i++) { entitys[i].draw(gfx); }
I have a vector in my gameworld class. When I add push a guitext entity to this vector I expect it to call the guitext::draw() function. But the base class function is being called. What am I doing wrong?
You made a vector of entity. Those objects always have type entity. If you want to invoke polymorphism, they need to be pointers or references. How can a vector of entity store a guitext? There's not enough space, it doesn't know how to destroy it, etc etc.
Was the vector declared as vector<entity>? Then only the base class part can be stored there, i.e. you lose polymorphism (which only works through pointer or reference in C++).
What you've done is a bit concealed variant of slicing.
You should define entitys to contain pointers to entity. Slightly edited example derived from your code.
#include "stdafx.h"
#include <vector>
#include <string>
class entity
{
public:
virtual void draw() { }
};
class guitext : public entity
{
public:
void draw()
{
printf("draw");
}
};
int _tmain(int argc, _TCHAR* argv[])
{
std::vector<entity *> entitys;
guitext g;
entitys.push_back(&g);
for(int i = 0; i < (int)entitys.size(); i++)
{
entitys[i]->draw();
}
return 0;
}
You're storing Entitys, not pointers to objects of varying derived types of Entity.
In addition, in your case it's not good idea to pass arguments by value, i suppose there will be very big quantity of objects that need to be redrawed. Better, by const reference, since functon doesn't change state of passed object inside.