带有类的C++中的GLUT代码

GLUT code in C++ with classes

本文关键字:中的 GLUT 代码 C++      更新时间:2023-10-16

下面是绘制矩形的代码,但我在glutdisplayFunc()中遇到了一个错误。我该怎么修?

#include <iostream>
#include <glut.h>
using namespace std;
class GUI
{
  public:
    int W,H;
    GUI()
    {
        W = 800;
        H = 600;
        glClearColor(0, 0, 0, 0);
        gluOrtho2D(-W, W, -H, H);
        glMatrixMode(GL_PROJECTION);
    }
    void display()
    {
        glBegin(GL_POLYGON);
        glVertex2d(-500, 300);
        glVertex2d(500, 300);
        glVertex2d(500, -300);
        glVertex2d(-500, -300);
        glEnd();
        glFlush();
    }
};
int main(int argv, char **argc)
{
    GUI ob;
    glutInit(&argv, argc);
    glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE);
    glutInitWindowSize(ob.W, ob.H);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("Queen Problem");
    glutDisplayFunc(ob.display);      //Error
    glutMainLoop();
    return 0;
}

我正在使用Visual;工作室;2010年。我在OpenGL中创建了一些程序,但没有任何冲突。这是我第一次在OpenGL中使用类。

错误为:

错误1错误C3867:"GUI::display":函数调用缺少参数列表;使用'&GUI::display'以创建指向成员的指针。

我尝试使用&GUI::display,但它也导致了错误。

C++和C不共享相同的链接和ABI。此外,对于类,还有一个称为"this"指针的"隐式"参数,该参数是隐藏的并为您解析。在内部,这将改变您所期望的函数签名,编译器会处理细节以确保这一点有效。C函数调用需要对具有所需签名的函数的引用。它也没有办法直接互操作,您必须以某种方式桥接它。

  • 您收到错误消息的原因是,您将函数display()定义为GUI类的成员函数,或者您没有将display()函数定义为GUI类别的成员,并且您正试图从GUI类别调用它
  • 要解决这个问题,您需要将display()函数定义为GUI的非成员函数,不带任何输入参数。如果它是非成员函数,则不能执行此操作。ob.display.glutDisplayFunc不接受成员函数
  • 要引用GUI类上的非成员函数display(),需要这样调用它
  • glutDisplayFunc(&display)

C++没有称为";"闭包"

此外,GLUT是一个C API,这意味着即使C++支持闭包,GLUT也不知道如何使用它。

所以你必须使用一个非成员函数,使用它来调用实例上的类成员函数。大多数C API允许您提供回调参数(通常以void*的形式)。但是GLUT并不能做到这一点,所以实际上您只能调用类的全局实例。

更新

您的代码还有其他问题。在出现OpenGL上下文之前,先安装GUI。OpenGL上下文由glutCreateWindow创建。但是"GUI"构造函数进行OpenGL调用,如果没有可用的构造函数,这些调用将无效。

更糟糕的是:构造函数中的所有调用实际上都属于绘图代码。

解决方案

  1. 使display为静态
  2. 或者去掉GUI类。如果你只有一个窗口,你其实并不需要它
  3. 制作GUI类的单个全局实例,并从供过于求显示回调中调用其display()方法
  4. 或者使用不同的库来初始化OpenGL
  5. 或者想办法通过";这个";指针穿过供过于求

解释

在C++类中,方法有隐藏的this参数,除非它是静态的。如果没有this指针,就不能调用非静态类成员。

GLUT需要一个没有this参数的函数。

如果您不知道CCD_;指针是,你需要得到一本C++书和学习更多。

要么制造";显示";static(在这种情况下,您将无法从方法中访问类成员),或者找到某种方法来传递";这个";要在中使用的指针。

通过供过于求传递this指针并将调用转发给一个类,如下所示:

class Gui{
public:
    void display();
};
void* getWindowData(int id);
void setWindowData(int id, void* p);
void displayForwarded(){
    Gui *gui = (Gui*)getWindowData();      
    if (gui)
        gui->display();
}
int main(int argc, char** argv){
    ....
    int windowId = glutCreateWindow();       
    Gui gui;
    setWindowData(windowId, &gui);
    glutDisplayFunc(displayForwarder);
}

问题在于getWindowData()setWindowData()的内容。如果您使用的是OpenGLUT,您可以在其中使用glutSetWindowData函数。

在FreeGLUT中,你可以滥用窗口标题来传递指针(坏主意,不要这样做),但这是一种糟糕的体验。

所以剩下的就是创建一个全局映射,通过它将窗口id转换为用户数据指针和用户数据。

typedef int WindowId;
typedef std::map<WindowId, Gui*> GuiMap;
namespace Internal{
     GuiMap guiMap;
}
class Gui{
public:
    ...
    void display();
}
void setWindowGui(WindowId id, Gui* p){
     Inertnal::guiMap[id] = p; // guiMap.insert(std::make_pair(id, p))
}
Gui* getWindowGui(WindowId id){
     GuiMap::iterator found = Internal.guiMap.find(id);
     if (found == Internal.guiMap.end())
         return 0;
     return found.second;
}
void displayForwarder(){
     WindowId = getGetWindow();//glut function
     Gui *gui = getWindowGui(id);
     if (!gui)
         throw std::string("gui not found");
     gui->display();
}
int main(int argc, char** argv){
    ...
    Gui gui;
    WindowId window = glutCreateWindow(.....);...
    setWindowGuiwindow, &gui);
    glutDisplayFunc(displayForwarder);
    ...
    ...
}

如果你不明白答案,那就拿一本C++书读一读。