【问题标题】:GLUT code in C++ with classes [duplicate]带有类的C ++中的GLUT代码[重复]
【发布时间】:2013-08-31 17:20:07
【问题描述】:

以下是绘制矩形的代码,但在 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 Studio 2010。我在OpenGL 中创建了一些程序,但没有任何类。这是我在 OpenGL 中使用类的第一次体验。

错误是:

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

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

【问题讨论】:

  • 您的成员函数甚至不使用该类。使其成为免费功能。
  • 只是为了完全清楚这是一个 GLUT 和 C++ 问题而不是 C++ 和 OpenGL 问题。 OpenGL 本身在其 API 中没有任何回调。还有其他像 glfw 这样的 OpenGL 辅助 API 没有这个问题
  • 您正在处理的是 C 和 C++ 之间的低级互操作问题。这与 OpenGL 甚至 GLUT 无关。 GLUT 是用 C 编写的,需要一个 C 函数,但是您必须在 C++ 中解决这个问题才能提供它。如果您发现提供的答案难以理解,那么问题最终将回到对 C、C++ 缺乏了解。虽然我喜欢反复试验,但你在喷水和祈祷,这在 C/C++ 中是不容易容忍的。
  • @PeterT:“OpenGL 本身在其 API 中没有任何回调”glu 库有它们。见gluTessCallback
  • @SigTerm glu 不是 OpenGL 的一部分,它建立在 OpenGL 之上。鉴于规范的最后一次更新似乎是 1998 年,并且此后已被弃用,我认为可以肯定地说 glu 不应该在新项目中使用,尤其是对于 OpenGL 版本 >=3

标签: c++ glut


【解决方案1】:

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

【讨论】:

    【解决方案2】:
    • 您收到错误消息的原因是因为您将函数 display() 定义为 GUI 类的成员函数,或者您没有将 display() 函数定义为 GUI 类的成员并且您试图从 GUI 类调用它。
    • 要解决此问题,您需要将 display() 函数定义为不带输入参数的 GUI 非成员函数。如果它是一个非成员函数,你不能这样做 ob.display。 glutDisplayFunc 不采用成员函数。
    • 要引用GUI类的非成员函数display(),需要这样调用;
    • glutDisplayFunc(&display);

    【讨论】:

      【解决方案3】:

      C++没有“闭包”概念。闭包是一个元组,由一个函数和一个执行函数的作用域组成。类成员函数需要一个类实例才能使用。由于 C++ 中没有这个概念,所以不能获取实例成员函数的函数指针。

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

      因此,您必须使用非成员函数来调用实例上的类成员函数。大多数 C API 允许您提供回调参数(通常以 void* 的形式)。然而 GLUT 并没有这样做,因此您只能调用该类的全局实例。

      更新

      您的代码还有其他问题。您在 OpenGL 上下文之前实例化 GUI。 OpenGL 上下文由glutCreateWindow 创建。但是 `GUI' 构造函数会调用 OpenGL,如果没有可用的构造函数,这些调用是无效的。

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

      【讨论】:

      • 静态成员函数不需要工作。 extern "C" 免费功能是。见stackoverflow.com/questions/1738313/…
      • @chris:谢谢。我更不喜欢 C++ 的一个原因 ;)
      • 是的,我希望我不必使用 C 接口来将它与任何其他语言一起使用(至少是简单的方法)。
      • @chris:使用 C 接口是最简单的方法。做 OOP 接口,两个不同的程序员永远不会同意谁的类层次结构/编码风格是“正确的”。
      • "so is use a extern "C"" 这是不正确的。 Extern "C" 只处理名称修改。这仅在您制作 dll 时才重要。只要调用约定与 glut 要求的调用约定相匹配,extern "C" 就没有任何区别。
      【解决方案4】:

      解决方案

      1. display设为静态。
      2. 或者去掉 GUI 类。如果你只有一个窗口,你就不需要它。
      3. 创建一个 GUI 类的全局实例,并从 glut 显示回调中调用其 display() 方法。
      4. 或者使用different library来初始化OpenGL。
      5. 或者想办法通过 glut 传递“this”指针。

      说明

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

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

      如果你不知道this"指针是什么,你需要买一本C++书,多学习。

      要么将“显示”设为静态(在这种情况下,您将无法从方法中访问类成员),或者找到某种方法来传递“this”指针以供在其中使用。

      通过 glut 传递 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++ 的书读一读。

      【讨论】:

        猜你喜欢
        • 2010-09-08
        • 2010-09-08
        • 1970-01-01
        • 2017-04-18
        • 2017-03-22
        • 2012-01-04
        • 2015-03-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多