2

I have two classes, Messaging and GameObject. Each GameObject object has an instance of Messaging and I need to have a function pointer in Messaging pointing to a function in GameObject.

Furthermore there will also be objects from classes that derive from GameObject that should have the same (have function pointer in their Messaging instance pointing to a function in them).

Below is the code where a GameCharacter object (derived from GameObject) supply the function to be called to its instance of Messaging:

messaging->Register(GameCharacter::DoMessage);

Here is my Messaging class code:

/// Allows an object to send and receive messages.
class Messaging : public Component, public ::Messaging
{
private:

    // Forward declaration of GameObject
    class GameObject {};

    // Define the OnMessageType as a function pointer to a function
    // taking Message as parameter and returning void.
    typedef void (GameObject:: *OnMessageType)(Message);

    // OnMessage function pointer;
    OnMessageType OnMessage;

public:

    // Assign a function to the function pointer
    void Register(OnMessageType func) { OnMessage = func; }

    // Forward the Message to the function pointed to by the function pointer
    void DoMessage(Message msg) { (this->*OnMessage)(msg); };

};

The GameObject class:

class GameObject
{
    public:

        /// Unique number used for identification
        int id;

        /// Reference to the graphical model displayed by this object
        int modelReference;

        /// GameObject children
        std::vector<GameObject> children;

        /// Constructor
        GameObject();

        /// Destructor
        ~GameObject();

        /// Add a child GameObject node
        void AddChild(GameObject child);

        /// Update Object
        virtual void Update();

        /// Handles received messages
        //virtual void DoMessage(Message msg);

        // Provide pointers to all possible components
        Components::Transform* transform;
        Components::RigidBody* rigidBody;
        Components::Messaging* messaging;

        // Pointer to message queue
        //std::vector<Message> *msgQueue;

    private:
        /// Send message
        void SendMessage(Message msg);
};

The GameObject object would call Register with the function which OnMessage should point to. Then when DoMessage is called the function pointed to in GameObject should be called. So in this case calling DoMessage (in the Messaging instance of GameCharacter) should in turn call DoMessage in the GameCharacter object.

The problem is that I get this error on the DoMessage(Message msg) function:

pointer to member type 'void (Components::Messaging::GameObject::)(Message)' incompatible with object type 'Components::Messaging'

from what I can gather its unhappy about the pointer function types. I have read (on stack overflow posts) that when calling the pointer function one should specify the type to which the member function belong but I can not find how to do that...

Could anybody shed some light on this and explain how I can fix my code?

Avalan
  • 149
  • 1
  • 10

2 Answers2

2

Use std::function with std::bind instead of function pointers. The reason you receive such an error is that you do not have an object to receive a function call but you have only a function. If you need to call a member function by its pointer you have to retain two things:

  1. a function pointer
  2. an object of a class which member function pointer you retained

The best way to implement what you want is to use std::function with std::bind. Example:

using namespace std::placeholders;
GameCharacter gameCharacter;
messaging->Register(std::bind(GameCharacter::DoMessage, gameCharacter, _1));

And Messaging class must accept std::function<void(Message)> object type.

class Messaging : public Component, public ::Messaging
{
private:

    // Forward declaration of GameObject
    class GameObject {};

    // Define the OnMessageType as a function pointer to a function
    // taking Message as parameter and returning void.
    //typedef void (GameObject:: *OnMessageType)(Message);
    typedef std::function<void(Message)> OnMessageType;

    // OnMessage function pointer;
    OnMessageType OnMessage;

public:

    // Assign a function to the function pointer
    void Register(OnMessageType func) { OnMessage = func; }

    // Forward the Message to the function pointed to by the function pointer
    void DoMessage(Message msg) { this->OnMessage(msg); };

};
Toby Speight
  • 23,550
  • 47
  • 57
  • 84
fnc12
  • 2,113
  • 1
  • 18
  • 25
  • 1
    An [even better](http://stackoverflow.com/questions/17363003/why-use-stdbind-over-lambdas-in-c14) best way to implement this would be to use a lambda capturing the `GameCharacter` object instead of `std::bind`. – ComicSansMS Mar 07 '17 at 15:50
  • 1
    @Jarod42: That seems to work but now messaging->Register(GameCharacter::DoMessage) is complaining with: " no matching function for call to 'Components::Messaging::Register()' " any idea why? Must say I am out of my depth here and will have to read up on this. – Avalan Mar 07 '17 at 18:26
  • 1
    @fnc12: This looks like a clean solution but at the moment I am having trouble getting Eclipse to recognize std::function. I have included but still can't find it. Think I need to enable c++11 first... – Avalan Mar 07 '17 at 18:34
  • @Avalan Don't use eclipse. It is horrible. What is your dev platform and target platform? – fnc12 Mar 07 '17 at 18:53
  • @fnc12: At the moment I am developing for Windows7 and might port to Linux in the future. Using Eclipse Neon with MinGW compiler. Normally I use Visual Studio but thought I give Eclipse a go... Maybe not the best idea... – Avalan Mar 07 '17 at 19:02
  • 1
    @fnc12: I got Eclipse to recognize std::function and the code now compiles fine but crash when running it... I will just slowly go though everything again... – Avalan Mar 07 '17 at 19:04
  • We can discuss your code together online if you wish - I'm interested in your project especially for observer pattern. Hit me on skype `fnc1234` if you want. Thanks – fnc12 Mar 07 '17 at 19:45
  • 1
    Its working now! Thanks! Crash was caused by not thinking straight and creating the gameObject object inside the GameObject constructor :-) At the moment I am experimenting with a basic game engine and as you might have guessed this is part of the implementation of the messaging system. – Avalan Mar 07 '17 at 21:11
  • @Avalan That's cool! Yes I guessed about it. Also I have xp in creating game with cocos2d-x with C++ and EntityX/anax component-entity-system libs and currently reading `Game design patterns` book – fnc12 Mar 08 '17 at 06:10
1

Messaging doesn't inherit from GameObject so you cannot use this instance to call OnMessage.

You need an instance of GameObject to call member method.

 GameObject gameObject;

 (gameObject.*OnMessage)(msg);
 // or (gameObject.*this->OnMessage)(msg);

But not sure it is what you want to do.

Maybe you really want a std::function<void(Message )>...

Jarod42
  • 173,454
  • 13
  • 146
  • 250
  • @Quentin: Typo, and i don't want to use cast, just use the instance I define just before. Fixed now. – Jarod42 Mar 07 '17 at 12:54
  • Are you sure this compiles ? `OnMessage` is not a member of `GameObject` class (but of `Messaging` class). – user Mar 07 '17 at 15:17
  • @Quentin: Code should work before your "fix". Whereas mine was explicit that `OnMessage` is a member. – Jarod42 Mar 07 '17 at 15:35
  • @Jarod42 Oh, my bad! I mixed up the operator precedence in there, thought `gameObject.*this` would be bound first (and thus fail). Sorry for that! – Quentin Mar 07 '17 at 16:34