storing, parsing through and executing stored member functions - c++

I'm currently working on some code and need to make something like an event handler that I can register explicit events and store them into a vector that I can loop through in my main listen() function. I'm missing something about pointers that I cant pinpoint with docs and a google search and need help figuring out why my compilers asking for a pointer to a member.
I've tried creating a typedef with a member function definition but I have the problem of it not compiling currently with a "non standard syntax, put an & to create a pointer to a member." error.
class Obj {
private:
typedef int (Obj::*Event) (std::vector<std::string> in);
std::vector<Event> events;
int exampleEvent(std::vector<std::string> input);
public:
Obj();
int regEvent(Event ev);
int listen();
}
example event code
int Obj::exampleEvent(std::vector<std::string> input)
{
// heres my app logic
return 0;
}
register events in constructor
Obj::Obj()
{
regEvent(exampleEvent); // exampleEvent: non-standard syntax; use
//'&' to create a pointer to member
}
listen, and add event to vector.
int Obj::regEvent(Event ev)
{
events.push_back(ev);
return 0;
}
// listen for command input
int Obj::listen()
{
// get input
string str;
getline(cin, str);
vector<string> input = split(str, " ");
// loop through events
for (auto ev : events)
{
ev(input); // <-- Term does not evaluate to function taking 1 arg.
}
return 0;
}

Obj::Obj()
{
regEvent(exampleEvent); // exampleEvent: non-standard syntax; use
//'&' to create a pointer to member
}
must be
Obj::Obj()
{
regEvent(&Obj::exampleEvent);
}
and
for (auto ev : events)
{
ev(input); // <-- Term does not evaluate to function taking 1 arg.
}
must be
for (auto ev : events)
{
(this->*ev)(input);
}

Exxpected syntax is:
regEvent(&Obj::exampleEvent);

Related

GLFW keycallback userpointer not carrying data

I'm trying to send data from my application to the GLFW keyCallback where I then access and modify that data. However, nothing I pass in can be accessed or changed without an app crash. What am I doing wrong?
//main.cpp
typedef struct
{
string type, name;
} DebugUsrPtr;
//hot loop
{
DebugUsrPtr myPtr;
myPtr.type = "aaa";
myPtr.name = "bbb";
void *testPtr = &myPtr;
glfwSetWindowUserPointer(myWin, testPtr);
glfwSetKeyCallback(myWin, keyCallback0);
glfwSetWindowUserPointer(myWin, myWin);
}
//input.cpp
void keyCallback0(GLFWwindow *window, int key, int scancode, int action, int mods)
{
auto *myTest = static_cast<DebugUsrPtr*>(glfwGetWindowUserPointer(window));
cout << "name test = " << myTest->name << endl; // ""
myTest->name = "zzzz"; //prints "zzzz" for one frame then appcrash
}
On this line:
glfwSetWindowUserPointer(myWin, myWin);
When you set that, the user pointer will now point to the window structure, not your struct. So when the callback is called (it is called later), it no longer points to your debug structure, but to the windows pointer.
You need to send the pointer to your structure and let it there as long as you think you will need it.
You have another error, the debug structure is destroyed before the callback is called:
{
DebugUsrPtr myPtr;
myPtr.type = "aaa";
myPtr.name = "bbb";
void *testPtr = &myPtr;
glfwSetWindowUserPointer(myWin, testPtr);
glfwSetKeyCallback(myWin, keyCallback0);
glfwSetWindowUserPointer(myWin, myWin);
} // debug structure destroyed here!
So when the callback is called later, it the debugs structure will be freed, and that will lead to undefined behaviour!
For that, I think you should declare your struct in the parent scope of your event loop. Just like this:
DebugUsrPtr myPtr;
// ...
{
glfwSetWindowUserPointer(myWin, &myPtr);
glfwPollEvents(); // the callback will be called here if user press keys!
}
If you're really doing C++, declare your struct like this instead:
struct DebugUsrPtr {
std::string type, name;
};
If you want a different type or a different pointer for each callback, hold them all in a bigger struct:
struct AllPointers {
DebugUsrPtr dbg;
MouseUsrPtr mouse;
// more...
};

Deleting an element in a vector by value

How can I retrieve an object from the Flight to be compared to the input (flightNumber) in the main? How do I declare the attributes type in the main?
When I compile, a error message is displayed: invalid conversion of 'int' to '*Flight*' at agent1.delete(flightNumber);.
class Flight
{
int FlightNumber
};
class TravelAgent
{
vector <Flight *> flightList;
};
void Agent::delete(Flight *obj)
{
vector<Flight*>::iterator ptr;
for(ptr=flightList.begin();ptr!=flightList.end();ptr++)
{
if((*Ptr)==obj)
{
flightList.erase(ptr);
break;
}
}
if ((ptr) == flightList.end())
{
cout<<"Flight not found"<<endl;
}
}
int main
{
Agent agent1;
int flightNumber;
cout<<"Enter the number of the flight: "<<flush;
in>>flightNumber;
agent1.delete(flightNumber);
}
You can add(if not present) a getter in Flight class
class Flight{
int FlightNumber;
public:
int getflightNumber(){ return flightNumber;}
};
and go as following:-
void Agent::delete(int flightNumber)
{
vector<Flight*>::iterator ptr;
for(ptr=flightList.begin();ptr!=flightList.end();ptr++)
{
if(((*Ptr)->getflightNumber() == flightNumber)
{
flightList.erase(ptr);
break;
}
}
if ((fPtr) == listFlight.end())
{
cout<<"Flight not found"<<endl;
}
}
Since the code here isn't fully functional, it's hard to give you good advice.
First, your error happens because you call (what seems to be) the member function, void Agent::delete(Flight *obj), with a variable of type int instead of type Flight. The compiler is not able to interpret your Flight object as an int, so it throws an error.
Secondly, you want to know how to retrieve attributes from an object. I will advise you to have a look to accessors and mutators.
If you want to retrieve information hold in your Flight object, you should expose member functions allowing that.
// in your header file
class Flight
{
private:
int flight_number;
public:
// retrieve flight number value
int get_flight_number(void) const;
// allow to set the flight number value
void set_flight_number(int new_flight_number);
// some other member functions
}
// in your source file
int Flight::get_flight_number(void) const
{
return this->flight_number;
}
void Flight::set_flight_number(int new_flight_number)
{
// let's do some verification (do whatever you want)
if (new_flight_number > 0)
{
this->flight_number = new_flight_number;
}
}
This way you will be able to set and access your flight_number by writing, for example :
void test_function(Flight *f)
{
if (f->get_flight_number() == 42)
{
// do some stuff
}
}
int main()
{
Flight *my_f = new Flight();
my_f->set_flight_number = 4242;
my_test_function(my_f);
}
Now, you have enough information to get going.
NOTES :
You heavily use pointers. Modern C++ strongly tends to not! Try to use references or move operation. You can consult this pages for info:
cpp-reference - references
cpp-reference - move semantics
It's a bit hardcore for beginner though. The web is full of great article. about it
You original error is in your main method. You need to change it so that instead of passing the flight number to your delete method, you create an instance of your Flight class.
int main() { // you are also missing parenthesis
Agent agent1;
int flightNumber;
cout<<"Enter the number of the flight: "<<flush; // I don't know what flush is but maybe you meant std::endl
cin>>flightNumber;
Flight flight(flightNumber);
agent1.delete(&flight); // delete takes a Flight* not an int
}
This requires that your Flight class have an appropriate constructor.
class Flight
{
public:
Flight(int flightNumber)
: flightNumber_(flightNumber)
{}
private:
int flightNumber_;
};
Then in your delete method you search your vector for the Flight instance that has the same flightNumber_ as the Flight you want to remove from your vector. This will require your Flight class to have some way of returning it's flightNumber_ member variable.
This is definitely NOT the best way to do this and is far from being in accordance with modern C++ standards but it should get you going.

Array of functions that can be called like 'funs[1]();'

I'm working on a Visual C++ 2010 Express console application.
Before I go into detail, the summary here is: How can I make an array/list/vector of functions and call them from that array?
So I'm having a little difficulty with function pointers. I'm writing a 'Terminal' class, which in turn has a member class 'CommandMap'. The purpose of the CommandMap class is to store a vector/array of functions and the strings that represent them in another vector/array. I want the functions to be called (only) when the class calls them from the vector, but it executed only when I added it to the vector and not when trying to call it.
I tried defining a type for it:
typedef void (*CmdCallback)();
I declared a vector to contain them:
vector<string> CmdNames;
vector<CmdCallback> CmdFuncs;
I add them like so:
// Map a new command
bool CommandMap::Map(string name, CmdCallback func)
{
if (!IsNullOrSpace(name) && func != NULL)
{
if (!Exists(name))
{
CmdNames.push_back(name);
CmdFuncs.push_back(func);
return true;
}
}
return false;
}
And I try calling them like this:
// Get a command callback from its identifier
CmdCallback CommandMap::GetFunc(string name)
{
int index = IndexOf(name);
if (index == -1) return NULL;
else return CmdFuncs.at(index);
}
// If the given string is a command indentifier
// it will invoke the associated callback.
bool CommandMap::Exec(string input)
{
for each (string id in CmdStrings)
{
if (input == id)
{
CmdCallback cmd;
cmd = GetFunc(id);
cmd();
return true;
}
}
return false;
}
I tried using this:
CmdCallback SayHello()
{
cout << "Hello World!" << endl;
return NULL; // Forces me to return null, guessing since it's
// not 'void' but a 'void' pointer it must return something
}
int main(int argc, char *argv[])
{
App = new Terminal(argc, argv);
App->Commands->Map("say", SayHello);
while (!App->ExecComplete)
{
App->WaitEnter();
App->Commands->Exec("say");
App->WaitEnter();
App->ExecComplete = true;
}
return App->ExitCode;
}
This works, at first. The function gets called when I try to Map() it though. And when I Exec() "say", it finds the callback, but when it tries to call it, I get this runtime error, to which I can see no detail other than the option to break or continue. The code it gives me is.
I pretty much want to abandon my method and try a new approach, maybe I'm going the wrong way with the void pointer typedef, and I need to throw a '&' or a '*' somewhere I haven't like in the Map() argument list. Maybe a vector isn't the best way to do this either.
Basically, I am asking how I can I make an array of functions that can (and only) be called by referencing them from the array. I'm terrible with callbacks.
You can use std::functions, or, if you don't have C++11 support, boost::function. These are function object wrappers that can be easily constructed from free or member functions. You can store these in a standard library container or simple array.
If I understand correctly you actually want to declare SayHello as void SayHello() so that a pointer to SayHello has the type void (*)() (i.e. CmdCallback) which is what you need for your vector of functions.

What's wrong with this class?

I think the problem is in main() but this compiles fine but I get no output. I think maybe it's not initalizing correctly because in debug mode it says
"myCharQ {item=0x0018fa00 "ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ̺yâpú" front=-858993460 rear=-858993460 ...}"
How would you rewrite this so that it is proper? I'm just starting out with classes so any help would be useful.
The following is a Array based Queue class
#include <iostream>
#include <cstdlib>
using namespace std;
const int MaxQueueSize = 10; // Queue Struct can hold up to 10 char.
typedef char ItemType; // the queue's data type is char
class CPPQueue
{
public:
CPPQueue();
ItemType item[MaxQueueSize];
void initQueue(CPPQueue q);
bool IsEmpty(CPPQueue q);
bool IsFull(CPPQueue q);
void Enqueue(CPPQueue q, ItemType newItem);
void PrintQ(const CPPQueue q);
void PrintQueueInfo(CPPQueue myQ);
ItemType Dequeue(CPPQueue q);
private:
int front, rear;
int count;
};
CPPQueue::CPPQueue()
{
int front, rear, count = 0;
}
void CPPQueue::initQueue(CPPQueue q)
{
q.front = q.rear = q.count = 0;
}
bool CPPQueue::IsEmpty(CPPQueue q)
{
return (q.count == 0);
}
bool CPPQueue::IsFull(CPPQueue q)
{
return (q.count == MaxQueueSize);
}
void CPPQueue::Enqueue(CPPQueue q, ItemType newItem)
{
if(q.count == MaxQueueSize)
{
cerr << "Error! Queue is full, cannot enqueue item.\n" << endl;
exit(1);
}
q.item[q.rear] = newItem;
q.rear++;
if (q.rear == MaxQueueSize)
{
q.rear = 0; // adjustment for circular queue
}
q.count++;
}
ItemType CPPQueue::Dequeue(CPPQueue q)
{
ItemType theItem;
if(q.count == 0)
{
cerr << "Error! Queue is empty, cannot dequeue item.\n" << endl;
exit(1);
}
theItem = q.item[ q.front ];
q.front++;
if (q.front == MaxQueueSize)
{
q.front = 0; // adjustment for circular queue
}
q.count--;
return theItem;
}
// Function PrintQ() prints the contents of the queue without changing
// the queue. Printing starts at the "front" index and stops before we
// get to the "rear" index. A decrementing counter controls the loop.
//
void CPPQueue::PrintQ(const CPPQueue q)
{
int i;
int qindex = q.front;
for(i = q.count; i > 0; i--)
{
cout << q.item[qindex] ;
qindex = (++qindex) % MaxQueueSize; // adjustment for circular queue
if(i > 1)
cout << ", ";
}
}
// Helper function for the main program below.
void CPPQueue::PrintQueueInfo(CPPQueue myQ)
{
cout << "The queue contains: ";
PrintQ(myQ);
cout << endl;
}
int main()
{
CPPQueue myCharQ;// queue holds characters
char ch; // char dequeued
myCharQ.initQueue(myCharQ);
myCharQ.Enqueue(myCharQ, 'a'); myCharQ.PrintQueueInfo(myCharQ);
myCharQ.Enqueue(myCharQ, 'b'); myCharQ.PrintQueueInfo(myCharQ);
myCharQ.Enqueue(myCharQ, 'c'); myCharQ.PrintQueueInfo(myCharQ);
ch = myCharQ.Dequeue(myCharQ); myCharQ.PrintQueueInfo(myCharQ);
ch = myCharQ.Dequeue(myCharQ); myCharQ.PrintQueueInfo(myCharQ);
myCharQ.Enqueue(myCharQ, 'e');
myCharQ.Enqueue(myCharQ, 'f'); myCharQ.PrintQueueInfo(myCharQ);
myCharQ.Enqueue(myCharQ, 'g'); myCharQ.PrintQueueInfo(myCharQ);
cout << endl;
// print the dequeued characters
while(!myCharQ.IsEmpty(myCharQ))
{
ch = myCharQ.Dequeue(myCharQ);
cout << ch << " ";
}
cout << endl << endl;
return 0;
}
You never initialize the member variables front, rear, and count. You shadow them in your constructor by declaring variables with the same names again. Drop the int and just assign them (though this is not why the values aren't printed correctly, more on that in a bit). Actually, don't do that either; use an initializer list:
CPPQueue::CPPQueue()
: front(0), rear(0), count(0)
{ }
Also, why do you have an initQueue function? You already have a constructor, rely on that to initialize your instance(s) (this is not C!).
Next, functions like IsEmpty are non-static member functions, yet they don't operate on the current instance. Don't take a queue as a parameter, just return if the instance is empty, full, whatever. Your code would have to be used like this:
Queue q;
q.IsEmpty(q);
Just strange. All of your member functions operate this way. When you cann a member function an implicit pointer to the current instance is passed as a hidden parameter (this). Therefore, each time the function is called it operates within the context of the instance it was called upon. You don't need to take an instance as a parameter.
Also realize that all of your functions take their arguments by value. You are going to be creating copies of these queues like crazy. If you modify the argument it will not be seen by the caller. For example:
void CPPQueue::initQueue(CPPQueue q)
{
q.front = q.rear = q.count = 0;
}
That is essentially useless (aside from that fact that an initialize function is unnecessary). The changes to q.front, q.rear, and q.count will not be visible outside of that function as you are operating on a copy.
So even though your constructor is broken due to variable shadowing, this is why you still don't print what you expect to after calling initQueue. You are modifying a copy.
As for your implementation, it is not robust at all. You expose the underlying array to clients of your class. This is a bad idea. The items in a queue should not be directly accessible. What if I decide to muck with the array directly? Now all of your state variables are wrong. front, rear, and count are all potentially invalid as I have modified the state of the queue without going through any of your functions.
It's not even necessary; all I should be able to do is queue and dequeue items. That's it. That's what a queue does. It is not an array, if I want an array I will use one.
So, in summary, kudos on beginning to learn a relatively complex language. Keep at it and don't get discouraged, we all have to learn this stuff at some point.
EDIT: I have to run, but here is a quick rewrite of some of your class. I have removed your typedef for the item type. Why? It is unnecessary. You are not going to change it to another type per some platform or other environmental change, so the typedef only hurts the usability of your class. typedefs are good for things that may change (i.e., int32_t) for some environmental reason, but if they aren't helping you or clients of your code they are just one more thing to get in the way.
class CPPQueue
{
public:
CPPQueue();
bool IsEmpty() const;
bool IsFull() const;
void Enqueue(char newItem);
char Dequeue();
void PrintQ() const;
void PrintQueueInfo() const;
private:
char item[MaxQueueSize];
int front
int rear;
int count;
};
CPPQueue::CPPQueue()
: front(0), rear(0), count(0) { }
bool CPPQueue::IsEmpty() const
{
// you don't actually need the this pointer
// here, but I included it to make it clear
// that you are accessing the count variable
// for the current instance of a CPPQueue
return this->count == 0;
}
I hope this helps you rewrite the rest of your class, gotta go now. I added const in teh declaration of functions that should not mutate the internal state of a CPPQueue. Do a search for "const correctness" to get a better idea of why you would do such a thing. Good luck!
In your constructor:
int front, rear, count = 0;
is wrong. These are local variables that shadow your member variables.
You should use member initializers (with colon after your constructor name) instead.
Also note that you are passing by value all over the place - you probably want to pass by reference instead - look at each function parameter and ask yourself, "do I want a new copy of my parameter or do I want to refer to the same parameter (same memory location) that I passed in?"
CPPQueue::CPPQueue() :
front(0), rear(0), count(0)
{
}
Note: #OP this is elementary-level C++ - you need to read up and get your basics down or you will run into many, many much more difficult to fix problems further down the line.

Callback to non-static method

Think of your basic GLUT programs. They simply run from a main method and contain callbacks like `glutMouseFunc(MouseButton) where MouseButton is the name of a method.
What I have done is I have encapsulated the main file into a class, so that MouseButton is no longer a static function but has an instance. But doing this gives me a compilation error :
Error 2 error C3867: 'StartHand::MouseButton': function call missing argument list; use '&StartHand::MouseButton' to create a pointer to member c:\users\angeleyes\documents\visual studio 2008\projects\capstone ver 4\starthand.cpp 388 IK Engine
It is not possible to provide a code sample as the class is quite huge.
I have tried using this->MouseButton but that gives the same error. Can't a pointer to an instance function be given for callback?
As the error message says, you must use &StartHand::MouseButton syntax to get a pointer to a member function (ptmf); this is simply mandated as part of the language.
When using a ptmf, the function you are calling, glutMouseFunc in this case, must also expect to get a ptmf as a callback, otherwise using your non-static MouseButton won't work. Instead, a common technique is for callbacks to work with a user-supplied void* context, which can be the instance pointer—but the library doing the callbacks must explicitly allow this parameter. It's also important to make sure you match the ABI expected by the external library (the handle_mouse function below).
Since glut doesn't allow user-supplied context, you have to use another mechanism: associate your objects with glut's current window. It does provide a way to get the "current window", however, and I've used this to associate a void* with the window. Then you simply need to create a trampoline to do the type conversion and call the method.
Machinery:
#include <map>
int glutGetWindow() { return 0; } // make this example compile and run ##E##
typedef std::pair<void*, void (*)(void*,int,int,int,int)> MouseCallback;
typedef std::map<int, MouseCallback> MouseCallbacks;
MouseCallbacks mouse_callbacks;
extern "C" void handle_mouse(int button, int state, int x, int y) {
MouseCallbacks::iterator i = mouse_callbacks.find(glutGetWindow());
if (i != mouse_callbacks.end()) { // should always be true, but possibly not
// if deregistering and events arrive
i->second.second(i->second.first, button, state, x, y);
}
}
void set_mousefunc(
MouseCallback::first_type obj,
MouseCallback::second_type f
) {
assert(obj); // preconditions
assert(f);
mouse_callbacks[glutGetWindow()] = MouseCallback(obj, f);
//glutMouseFunc(handle_mouse); // uncomment in non-example ##E##
handle_mouse(0, 0, 0, 0); // pretend it's triggered immediately ##E##
}
void unset_mousefunc() {
MouseCallbacks::iterator i = mouse_callbacks.find(glutGetWindow());
if (i != mouse_callbacks.end()) {
mouse_callbacks.erase(i);
//glutMouseFunc(0); // uncomment in non-example ##E##
}
}
Example:
#include <iostream>
struct Example {
void MouseButton(int button, int state, int x, int y) {
std::cout << "callback\n";
}
static void MouseButtonCallback(
void* self, int button, int state, int x, int y
) {
static_cast<Example*>(self)->MouseButton(button, state, x, y);
}
};
int main() {
Example obj;
set_mousefunc(&obj, &Example::MouseButtonCallback);
return 0;
}
Notice that you don't call glutMouseFunc directly anymore; it is managed as part of [un]set_mousefunc.
Just in case it isn't clear: I've rewritten this answer so it should work for you and so that it avoids the C/C++ linkage issue being debated. It will compile and run as-is (without glut), and it should work with glut with only minor modification: comment or uncomment the 4 lines marked ##E##.
No, a pointer to an instance function can not be given to a callback function expecting a function pointer of a certain signature. Their signatures are different. It won't compile.
Generally such APIs allow you to pass in a void* as a "context" parameter. You pass in your object there, and write a wrapper function which takes the context as the callback. The wrapper casts it back to whatever class you were using, and calls the appropriate member function.
You can't replace a static callback with an instance one. When the caller calls your callback, on what instance whoul it call? In other words, how does the caller pass in the formal 'this' argument?
The solution is to have a static callback stub and pass the instance as argument, which implies the callee must accept an arbitrary pvoid that will pass back when invoking the callback. In the stub, you can then call the non-static method:
class C {
void f() {...}
static void F(void* p) {
C* pC = (C*)p;
pC->f();
}
}
C* pC = ...;
someComponent.setCallback(&C::F, pC);
Contrary to what everyone seems to be saying, you most definitely CAN use a non-static member function as a callback method. It requires special syntax designed specifically for getting pointers to non-static members, and special syntax to call that function on a specific instance of a class. See here for a discussion of the needed syntax.
Here is sample code that illustrates how this works:
#include <cstdlib>
#include <string>
#include <iostream>
#include <vector>
#include <sstream>
#include <algorithm>
using namespace std;
class Operational
{
public:
Operational(int value) : value_(value) {};
string FormatValue() const ;
private:
int value_;
};
string Operational::FormatValue() const
{
stringstream ss;
ss << "My value is " << value_;
return ss.str();
}
typedef string(Operational::*FormatFn)() const; // note the funky syntax
Operational make_oper(int val)
{
return Operational(val);
}
int main()
{
// build the list of objects with the instance callbacks we want to call
Operational ops[] = {1, 2, 3, 5, 8, 13};
size_t numOps = sizeof(ops)/sizeof(ops[0]);
// now call the instance callbacks
for( size_t i = 0; i < numOps; ++i )
{
// get the function pointer
FormatFn fn = &Operational::FormatValue;
// get a pointer to the instance
Operational* op = &ops[i];
// call the callback on the instance
string retval = (op->*fn)();
// display the output
cout << "The object # " << hex << (void*)op << " said: '" << retval << "'" << endl;
}
return 0;
}
The output of this program when I ran it on my machine was:
The object # 0017F938 said: 'My value is 1'
The object # 0017F93C said: 'My value is 2'
The object # 0017F940 said: 'My value is 3'
The object # 0017F944 said: 'My value is 5'
The object # 0017F948 said: 'My value is 8'
The object # 0017F94C said: 'My value is 13'
You cannot use a non-static member function in this case.
Basically the type of the argument expected by glutMouseFunc is
void (*)(int, int, int, int)
while the type of your non-static member function is
void (StartHand::*)(int, int, int, int)
First problem is that types don't really match.
Second, in order to be able to call that method, the callback would have to know which object ( i.e. "this" pointer ) your method belongs to ( that's pretty much why the types are different in the first place ).
And third, I think you're using the wrong syntax to retrieve the method's pointer. The right syntax should be: &StartHand::MouseButton.
So, you have to either make that method static or use some other static method that would know which StartHand pointer to use to call MouseButton.
The following works in c++ to define a c callback function, useful for example when using glut (glutDisplayFunc, glutKeyboardFunc, glutMouseFunc ...) when you only need a single instance of this class :
MyClass * ptr_global_instance = NULL;
extern "C" void mouse_buttons_callback(int button, int state, int x, int y) {
// c function call which calls your c++ class method
ptr_global_instance->mouse_buttons_cb(button, state, x, y);
}
void MyClass::mouse_buttons_cb(int button, int state, int x, int y) {
// this is actual body of callback - ie. if (button == GLUT_LEFT_BUTTON) ...
// implemented as a c++ method
}
void MyClass::setup_glut(int argc, char** argv) { // largely boilerplate glut setup
glutInit(&argc, argv);
// ... the usual suspects go here like glutInitWindowSize(900, 800); ...
setupMouseButtonCallback(); // <-- custom linkage of c++ to cb
// ... other glut setup calls here
}
void MyClass::setupMouseButtonCallback() {
// c++ method which registers c function callback
::ptr_global_instance = this;
::glutMouseFunc(::mouse_buttons_callback);
}
In your MyClass header we add :
void mouse_buttons_cb(int button, int state, int x, int y);
void setupMouseButtonCallback();
This also works using identical logic flows to setup your glut
call to glutDisplayFunc(display)