【问题标题】:C++: Reference and Pointer question (example regarding OpenGL)C++:参考和指针问题(关于 OpenGL 的示例)
【发布时间】:2011-01-02 05:34:34
【问题描述】:

我想加载纹理,然后让它们被多个对象使用。这行得通吗?

class Sprite
{
    GLuint* mTextures; // do I need this to also be a reference?

    Sprite( GLuint* textures ) // do I need this to also be a reference?
    {
        mTextures = textures;
    }

    void Draw( textureNumber )
    {
        glBindTexture( GL_TEXTURE_2D, mTextures[ textureNumber ] );
        // drawing code
    }
};

// normally these variables would be inputed, but I did this for simplicity.
const int NUMBER_OF_TEXTURES = 40;
const int WHICH_TEXTURE = 10;

void main()
{
    std::vector<GLuint> the_textures;
    the_textures.resize( NUMBER_OF_TEXTURES );

    glGenTextures( NUMBER_OF_TEXTURES, &the_textures[0] );

    // texture loading code

    Sprite the_sprite( &the_textures[0] );
    the_sprite.Draw( WHICH_TEXTURE );
}

我有什么不同的方法可以做到这一点,即使它会起作用?

谢谢。

【问题讨论】:

  • 只是一个注释。如果您将某些东西定义(而不是声明)作为参考,这通常意味着您的设计有问题。
  • @Falmarri,你是什么意思?您是否建议将类字段作为引用或将局部变量作为引用是错误的?
  • @Kos:我说的是定义一个类字段作为参考。
  • 听起来像是实现任何单个 UML 关联端点的自然方式,已知该端点在对象的整个生命周期内都是不变的。也可以使用 const 指针。

标签: c++ pointers opengl reference pass-by-reference


【解决方案1】:
  1. 是的,这工作
  2. 无需将它们作为参考:您存储/传递指针的副本(速度很快),并且您不打算在外部更改此指针
  3. 有许多不同的方法可以做到这一点,正确的方法取决于您的其他代码要求。

例如您可以使用纹理的全局实例:

纹理.cpp:

static std::vector load_once_textures();
std::vector<GLuint> const& get_textures()
{
    static std::vector<GLuint> const the_textures = load_once_textures();
    return the_textures;
}

std::vector load_once_textures()
{
    // loading
}

纹理.h

std::vector<GLuint> const& get_textures();

这是一种简单且足够安全的方法,因为纹理将被加载一次,并且加载不存在静态初始化顺序不明确的问题

【讨论】:

    【解决方案2】:

    这种特殊情况应该有效。但是,一旦“the_textures”超出范围,Sprite 持有的指针就会失效。这将是相同的,即使它是一个参考。 在这种情况下,我建议您将 std::vector 放在 Sprite 类中,并由该类实例拥有和管理。

    【讨论】:

    • 是的,我意识到范围问题。但在这种情况下,它在 main() 中,所以它永远不会超出范围。至于将vector 放在Sprite 类中,我必须为每个精灵重新加载纹理,这对性能不利。这就是为什么我想做像我的 OP 这样的事情。但是,Sprite 类可以引用向量吗?
    • 您的纹理只是 OpenGL 使用的 GLuint 标识符,因此复制 Sprite 对象内的矢量不会再次加载它们。
    • @tibur 是的,我意识到这一点。我认为 Jon Watte 的意思是在 main() 中没有任何 vector,而是在 Sprite 类中完成所有操作。
    • 我假设您使用的纹理加载器模块在加载给定文件名的第二次(和第三次......)时只返回相同的 GLuint。因此,“加载”成本可以忽略不计。如果您有 1,000 个相同精灵的实例,那么对象模板系统可能会有所帮助。要点:编写的代码是合法的。我只是不喜欢在一般情况下悬挂指针。
    【解决方案3】:

    我想知道为什么 Draw 不能只引用它正在绘制的对象。

    class Sprite
    {
    public:
    
        Sprite()
        {
        }
    
        void Draw( GLuint & texture )
        {
            glBindTexture( GL_TEXTURE_2D, texture );
            // drawing code
        }
    };
    
    • Sprite 是一种以特定方式绘制的类型
    • GLuint 是一种被绘制的类型

    这里的某处可能存在多态性: - 你有不同的绘图算法 - 在绘制的不同类型的对象中有多态(虚拟)方法

    所以 Draw 可能是一个虚方法,而 GLuint 可能是一个抽象基类,在这种情况下,实际的向量将不是对象,而是指向不同类型对象的指针。

    您当然应该将绘制对象的方式与存储对象的方式分离,因此在绘图类中存储一个向量,或者甚至传入一个假设它们在某种数组中的指针是不可能的是个好主意。

    顺便说一句,main 应该返回 int 而不是 void。

    【讨论】:

    • 我需要在Sprite 类中存储多个纹理......至于main(),我知道它应该返回一个int。但我想尽可能缩短示例代码,如果我将返回类型设置为int,那么我将不得不在最后添加return 0。或者如果我没有,有人会告诉我我忘了返回一个值......哈哈
    【解决方案4】:

    既然纹理 id 没有改变,那么在 Sprite 中使用 GLuint 值而不是存储 array-ptr 并选择要绘制的精灵怎么样?

    看起来更简单,无需担心范围

    除非您需要在退出应用程序之前调用 glDeleteTextures,否则我建议您创建一个 TextureMgr 类或一劳永逸地解决此问题的东西。 ;)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-05-13
      • 1970-01-01
      • 2023-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-09
      相关资源
      最近更新 更多