-1

After many hours of searching I still haven't found a solution to the following problem. In my game I make use of an abstract factory which generates objects. I'm trying to pass a function made in this factory, which generates bullets, to enemy. For this I tried using a function pointer which points to factory->getBullet() and passing it with the constructor of enemy. It failed :)

#include "Factory.h"
int main() 
{
    Factory* f = new Factory();
    f->getEnemy(&f->getBullet);
    return 0;
}

Factory.h

#include "Enemy.h";
#include "Bullet.h";
class Factory {
public:
    Factory();
    virtual ~Factory();
    Enemy* getEnemy(Bullet* (*getBulletPtr)(int));
    Bullet* getBullet(int damage);
};

Factory.cpp

#include "Factory.h"
Factory::Factory() {}
Factory::~Factory() {}

Enemy* Factory::getEnemy(Bullet* (*getBulletPtr)(int))
{return new Enemy(getBulletPtr);}

Bullet* Factory::getBullet(int damage)
{return new Bullet(damage);}

Enemy.h

#include "Bullet.h"
class Enemy
{
    private:
        Bullet* (*getBullet)(int) = NULL;
    public:
        Enemy(Bullet* (*getBulletPtr)(int));
        virtual ~Enemy();
};

Enemy.cpp

#include "Enemy.h"
Enemy::Enemy(Bullet* (*getBulletPtr)(int))
{
    getBullet = getBulletPtr;
    getBullet(10);
}

Enemy::~Enemy() {}

Bullet.h

#include <iostream>
using namespace std;

class Bullet {
public:
    Bullet(int damage);
    virtual ~Bullet();
};

Bullet.cpp

#include "Bullet.h"
Bullet::Bullet(int damage)
{
    cout << "This is a bullet: Damage:"<< damage << endl;
}

Bullet::~Bullet()
{}

When I try to run this code I get the following error:

ISO C++ forbids taking the address of a bound member function to form a pointer to member function.  Say '&Factory::getBullet' [-fpermissive]

When I change

f->getEnemy(&f->getBullet);

to

f->getEnemy(&Factory::getBullet);

I get the following error:

no matching function for call to 'Factory::getEnemy(Bullet* (Factory::*)(int))'

How can I pass factory->getBullet function to my enemies.

Any help would be appreciated!

  • A pointer to a non-member function is not the same thing as a pointer to a member function. – The Paramagnetic Croissant May 27 '14 at 17:50
  • 1
    possible duplicate of [this pointer and member function address](http://stackoverflow.com/questions/4669182/this-pointer-and-member-function-address) or better http://stackoverflow.com/questions/17035902/function-pointer-to-a-class-member – πάντα ῥεῖ May 27 '14 at 17:51
  • 1
    Offtopic: do you really need to pass a pointer to member function to another member function of same class? Anyway, please use google next time: [How do you pass a member function pointer?](http://stackoverflow.com/questions/130322/how-do-you-pass-a-member-function-pointer), [Parashift: Pointers to member functions](http://www.parashift.com/c++-faq/pointers-to-members.html). Oh, and don't forget about [std::function](http://en.cppreference.com/w/cpp/utility/functional/function) – Ivan Aksamentov - Drop May 27 '14 at 17:54
  • What I'm trying to achieve: I make an Enemy and the Enemy object makes Bullet objects by themself, for this I need to pass function pointer of factory::getBullet to enemy. – user3680711 May 27 '14 at 18:02
  • Why are you dynamically allocating a function in main, and *why are you not deleting the memory*? – Thomas Matthews May 27 '14 at 18:11
  • This was just a test project to show my problem. My real game project is much larger and more complex – user3680711 May 27 '14 at 18:16
  • Please verify that you want a pointer to a member versus a pointer to a function. Check out this FAQ: http://www.parashift.com/c++-faq/pointers-to-members.html – Thomas Matthews May 27 '14 at 18:36
  • @user3680711 pointer to free function and pointer to member function are *completely different*. Your code uses pointer to free function, it will never work to pass a member function to this. – M.M May 27 '14 at 21:57

1 Answers1

0

I believe you have a bad design. In general, a factory creates dynamically allocated objects of a common theme and returns a base pointer to the allocated object.

Also, most factories create the objects based on some kind of input, such as an ID value or a name or something similar:

struct Shape
{
  virtual const std::string& what_am_i(void) = 0;
};  // Common base class for shapes.

struct Triangle : public Shape
{
  const std::string& what_am_i(void)
  {
     const static std::string name = "triangle";
  }
};

Shape * Shape_Factory(const std::string& shape_name)
{
  Shape * p_object = NULL;
  if (shape_name == "triangle")
  {
    p_object = new Triangle;
  }
  return p_object;
}

You probably don't need a factory to create an enemy with a bullet, you could do this in a couple of statements (which cleans up your code):

int main(void)
{
  Bullet  b_15(15);
  Enemy   e(b_15);
  return EXIT_SUCCESS;
}

The above example creates an enemy with a 15 damage bullet. This is a different concept than an enemy receiving damage from a 15 damage bullet.

I suggest something like this for applying damage:

struct Weapon
{
  virtual unsigned int get_damage(void) const = 0;
};

struct Bullet : public Weapon
{
  unsigned int get_damage(void) const
  { return 15;}
};

struct Player
{
  virtual void receive_damage(const Weapon& w) = 0;
};

struct Enemy : public Player
{
  unsigned int life_points;
  void receive_damage(const Weapon& w)
  {
    unsigned int damage = w.get_damage();
    if (life_points > damage)
    {
        life_points -= damage;
    }
    else
    {
        life_points = 0;
    }
};

int main(void)
{
  Bullet b;
  Enemy e;
  e.receive_damage(b);
  return EXIT_SUCCESS;
}

A nice point about this design is that you can come up with different weapons, like arrows, that derive from Weapon and tell the Enemy to receive damage from the weapon.

The design expands nicely so that any Player (or class derived from Player) can receive damage from any class derived from Weapon.

Also notice, I have not used dynamic allocation, so I don't have any memory leak issues. Search your favorite reference for "smart pointer", "unique_ptr" or "scoped_pointer".

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154