Функция обратного вызова в freeglut от объекта - PullRequest
8 голосов
/ 15 февраля 2011

Я использую MSVC ++ и freeglut для использования openGL.Теперь у меня есть класс с именем Camera, который довольно прост, но он также содержит функцию для изменения формы моего окна.

Мой вопрос: как я могу установить glutReshapeFunc(void (*callback)(int,int)) для своей функции вмоя камера?

У меня есть следующий код, который не будет работать из-за ошибки компилятора:

int main(int argc, char **argv)
{
    Camera *camera = new Camera();
    glutReshapeFunc(camera->ReshapeCamera);
}

, и мой класс Camera выглядит следующим образом в Camera.h:

class Camera
{
public:
    Camera(void);
    ~Camera(void);
    void ReshapeCamera(int width, int height);
};

Возможно, это просто более общий вопрос обратного вызова, но единственное, что я обнаружил в Интернете, - это создание некоторого класса-обертки вокруг обратного вызова.Но не похоже, что это должно быть так сложно.Заранее спасибо.

Ответы [ 4 ]

10 голосов
/ 15 февраля 2011

Нет чистого способа сделать это. C не знает об объектах, поэтому указатели на элементы не работают. C не делает шаблонов, поэтому функторы не работают. API даже не позволяет вам передавать произвольный void *userData вашему обратному вызову, поэтому вы также не можете передавать объект таким же образом.

Таким образом, вам действительно нужно создать функцию-обертку, которая не является функцией-членом, и вам нужно как-то предоставить ей доступ к экземпляру объекта Camera через статическую и / или глобальную переменную.

Если это событие может прослушиваться несколькими объектами, вы можете создать одноэлементный класс, который позволяет регистрировать произвольных слушателей.

2 голосов
/ 15 февраля 2011

Вы не можете подключить его напрямую.ReshapeCamera - это функция-член, для запуска которой требуется экземпляр камеры.Обратный вызов glut - это функция C, у которой нет экземпляра камеры для вызова вашего метода.Вам необходимо создать функцию, которая будет вызывать метод изменения формы камеры.

1 голос
/ 16 февраля 2011

Это не имеет ничего общего с "C против C ++". Вам просто нужно понять, что влечет за собой вызов функции-члена и в основном то, к чему она сводится.

myObject.memberFunction(); // This is what the programmer sees.
memberFunction(&myObject); // This is what the compiler sees.

Функция-член - это необычное описание функции, которая просто принимает объект в качестве первого параметра. Он просто невидим в реальном списке параметров.

void MyClass::memberFunction() // This is the declaration the programmer sees.
void memberFunction(MyClass* this) // This is what the compiler sees.

С этого момента C ++ добавляет специальную семантику, чтобы упростить работу объектно-ориентированным способом. Таким образом, даже если ваш объект имеет функцию-член формата void (int, int), он на самом деле имеет формат void (Camera *, int, int) и не соответствует требуемому формату! Вот почему члены-статические функции могут использоваться для таких указателей функций . Вы когда-нибудь замечали, что статические функции-члены не могут получить доступ к членам "this"? Это связано с тем, что статические функции-члены не передают экземпляр объекта, представляющего this.

Фактически, вы можете эмулировать большую часть объектно-ориентированного программирования на простом языке C. Если вы сделаете набор функций, которые принимают указатель структуры в качестве первого параметра, вы получите много таких же преимуществ!

0 голосов
/ 05 августа 2013

Ниже показано, как зарегистрировать функцию обратного вызова c из c ++ Это обычно полезно, не специфично для перенасыщения.

Вот ваша клиентская программа на С ++

int main(int argc, char *argv[]) {

std::cout << "launching Camera ..." << std::endl;

Camera * camera = new Camera();

// ------ glut new window boilerplate ------- //

int WindowHandle = 0;
glutInit(&argc, argv);
WindowHandle = glutCreateWindow("hello there");
if(WindowHandle < 1) {
    std::cerr << "ERROR: Could not create a new rendering window" << std::endl;
    exit(EXIT_FAILURE);
}
// ------------------------------------------ //

camera->setup_callback();

glutMainLoop();

return 0;

}

Вот камера.cpp

Camera * ptr_global_instance = NULL;

extern "C" void ReshapeCamera_callback(int width, int height) {
    // c function call which calls your c++ class method
    ptr_global_instance->ReshapeCamera_cb(width, height);
}

void Camera::ReshapeCamera_cb(int width, int height) {
    std::cout << "width " << width << " height " << height << std::endl;
}

void Camera::setup_callback() {
    // c++ method which registers c function callback
    ::ptr_global_instance = this;
    ::glutReshapeFunc(::ReshapeCamera_callback);
}

и его заголовок Camera.h

class Camera {
public:
    void ReshapeCamera_cb(int width, int height);
    void setup_callback();
};

Обратите внимание на использование глобального указателя класса c ++ ptr_global_instance

...