简体   繁体   English

多种数据类型的C ++列表。 遗产?

[英]C++ list of multiple data types. Inheritance?

I have a lot of different classes. 我有很多不同的课程。 However they are all guaranteed to have certain methods such as render() and activate(). 但是,它们都可以保证具有某些方法,例如render()和Activate()。

My goal is to be able to store them all in 1 big list. 我的目标是能够将它们全部存储在一个大列表中。 Currently I have a big class called Container, and I do something like this to store the many objects I have. 当前,我有一个名为Container的大类,并且我做了类似的事情来存储我拥有的许多对象。

class Container{
public:

  BUTTON * buttons;
  int buttons_len;

  DRAW_AREA * draw_areas;
  int draw_areas_len;

  Container(){
      // constructor
  }

  void render(){
      for( int i = 0; i < buttons_len; i++ )
          buttons[i].render();

      for( int i = 0; i < draw_areas_len; i++ )
          draw_areas[i].render();
  }

};

The problem with this is that every time I want to add a new datatype, I have to modify multiple areas and it will become unwieldy in the future. 这样做的问题是,每当我要添加新的数据类型时,都必须修改多个区域,将来它将变得笨拙。 Whats a good way to do this ? 有什么好办法做到这一点?

I have looked into using templates, and from what I saw, I cant store classes with different "template vars" in the same list. 我已经研究过使用模板,从我看到的结果来看,我无法将具有不同“模板变量”的类存储在同一列表中。

Edit: forgot to mention that the render functions can be different render functions. 编辑:忘记提及渲染功能可以是不同的渲染功能。

Edit 2: 编辑2:

I got what I wanted to work. 我得到了我想工作的东西。 Not sure how good it is in terms of "good code" 不确定“好代码”方面有多好

Here is an example: 这是一个例子:

// abstract class
class Base{
public:
    virtual void render() = 0;
};


class Button : public Base{
public:
    int y;

    Button(){
        y = 10;
    }

    void render(){
        std::cout << "BUTTONS " << y << "\n";
    }

};


class Draw_Area : public Base{
public:
    int x;

    Draw_Area(){
        x = 5;
    }

    void render(){
        std::cout << "DRAW AREA " << x << "\n";
    }

    void extra(){
        std::cout << "extra draw_area\n" << x << "\n";
    }
};



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

    Base * test_1 = new Button();
    test_1->render();

    Base * test_2 = new Draw_Area();
    test_2->render();   


    Base * * test = new Base*[4];

    test[0] = new Button();
    test[1] = new Button();
    test[2] = new Draw_Area();
    test[3] = new Button();


    test[0]->render();
    test[1]->render();
    test[2]->render();
    test[3]->render();


    return 0;
}

Thanks for all the help ! 感谢您的帮助! the main 2 problems I had to deal with was making an abstract class to avoid object slicing, and storing the pointers to the classes and not the objects themselves in a list. 我要处理的主要2个问题是制作一个抽象类以避免对象切片,并将指向类的指针而不是对象本身存储在列表中。

I have a working Game - Shader Engine that uses modern OpenGL. 我有一个工作的游戏-使用现代OpenGL的着色器引擎。 This project has many components that are integrated together. 该项目具有集成在一起的许多组件。 The one thing that is used is a series of Manager Class objects that they themselves are all Singleton objects: 使用的一件事是一系列Manager Class对象,它们本身都是Singleton对象:

I can not show you the full class but I'll show the enumeration of the Singleton base class that contains all the derived singleton types: 我无法显示完整的类,但将显示包含所有派生的Singleton类型的Singleton基类的枚举:

class Singleton {
public:
    // Number Of Items In Enum Type Must Match The Number
    // Of Items And Order Of Items Stored In s_aSingletons
    enum SingletonType {
        TYPE_LOGGER = 0, // MUST BE FIRST!
        TYPE_SETTINGS,
        TYPE_ENGINE,
        TYPE_ANIMATION_MANAGER,
        TYPE_SHADER_MANAGER,
        TYPE_ASSET_STORAGE,
        TYPE_AUDIO_MANAGER,
        TYPE_FONT_MANAGER,
        TYPE_BATCH_MANAGER,     
    }; // Type;

    // More code below
}; // Singleton

These are objects that we only want a single instance during the life of the application or the game. 这些对象在应用程序或游戏的生命周期内只需要一个实例。


Now as for your example and question the ones of importance in the list above that would pertain to what you are trying to achieve are: 现在,作为您的示例,并质疑上面列表中与您要实现的目标有关的重要性:

  • ShaderManager 着色器管理器
  • AssetStorage 资产存储
  • BatchManager 批处理管理器

The others we can ignore since we aren't worried about Audio , Fonts , Animations , Game Settings , The Main Game Engine and the Logger although they are used through some of the objects listed above. 其他我们可以忽略的东西,因为我们不担心AudioFontsAnimationsGame SettingsThe Main Game EngineLogger尽管它们通过上面列出的某些对象使用。

The 3 above are integrated in such a way that the AssetStorage class will hold containers of all objects to be rendered. 上面的3种集成方式使得AssetStorage类将保存所有要呈现的对象的容器。 The AssetStorage also holds other important stuff such as loaded textures, fonts, audio files, gui controls sprites, models, etc.. The purpose of the AssetStorage class is that it acts as a database that is responsible for managing all of the memory of these objects. AssetStorage还包含其他重要内容,例如加载的纹理,字体,音频文件,GUI控件精灵,模型等AssetStorage类的目的是充当数据库的AssetStorage ,负责管理这些文件的所有内存对象。

It is the BatchManager's responsibility to send all the vertex data to be rendered, and this works based on a priority queue where that priority queue is determined by which Batch is the fullest or has the highest priority where that priority is based on Z-Depth . BatchManager's负责发送所有要渲染的顶点数据,并且此操作基于优先级队列,在该优先级队列中,优先级队列由哪个Batch highest priorityhighest priority确定,而该优先级基于Z-Depth When the BatchManager is ready to send the vertex data such as attributes and uniforms, matrices etc, then it looks into the ShaderManager to see what Shader Technique to apply to the ready to be rendered vertices, and then it sets the attributes and uniforms according. BatchManager准备好发送顶点数据(例如属性和ShaderManager ,矩阵等)时,它会查看ShaderManager以查看对要准备渲染的顶点应用何种Shader技术,然后根据其设置属性和均匀性。

This is a very complex beast; 这是一个非常复杂的野兽。 this is also not the only way to do this as there are other methods, especially when you begin to start rendering 3D Terrains and you have to construct a Scene Graph, BSP, Voxels, Marching Cubes etc. 这也不是唯一的方法,因为还有其他方法,尤其是当您开始开始渲染3D地形并且必须构造一个场景图,BSP,体素,行进立方体等时。

If you would like to learn more about the techniques described above you can visit Marek Knows and follow his OpenGL video tutorial series. 如果您想了解有关上述技术的更多信息,可以访问Marek Knows并遵循他的OpenGL视频教程系列。 However the methods described above are using Modern OpenGL and you would have to follow through his earlier series that used Deprecated - Legacy OpenGL 1.0 for that is how he has his website set up. 但是,上述方法使用的是Modern OpenGL,您必须按照他先前使用Deprecated-Legacy OpenGL 1.0的系列进行操作,这是他设置网站的方式。


What I can do is show you a small excerpt from the Asset Storage's header file so you can see the containers and methods of how this class "Stores" and "Manages" the memory of the Game's objects or "Assets". 我能做的是向您展示Asset Storage's头文件中的一小部分摘录,以便您可以看到此类“存储”和“管理”游戏对象或“资产”的内存的容器和方法。

AssetStorage.h 资产存储库

#ifndef ASSET_STORAGE_H
#define ASSET_STORAGE_H

#include "Singleton.h"
#include "CommonStructs.h"

namespace vmk {

class BaseMko;
class GuiElement;
enum GuiType;

struct Texture {
    bool        hasAlphaChannel;
    bool        generateMipMap;
    bool        wrapRepeat;
    unsigned    uWidth;
    unsigned    uHeight;
    TextureInfo::FilterQuality filterQuality;
    std::vector<unsigned char> vPixelData;

    Texture( TextureInfo::FilterQuality filterQualityIn, bool generateMipMapIn, bool wrapRepeatIn ) :
        hasAlphaChannel( false ),
        generateMipMap( generateMipMapIn ),
        wrapRepeat( wrapRepeatIn ),
        uWidth( 0 ),
        uHeight( 0 ),
        filterQuality( filterQualityIn )
    {}
}; // Texture

class AssetStorage sealed : public Singleton {
private:
    typedef std::unordered_map<std::string, std::shared_ptr<BaseMko>>       MapMkoAssets;
    typedef std::unordered_map<std::string, TextureInfo>                    MapTextureInfos;
    typedef std::unordered_map<std::string, std::shared_ptr<GuiElement>>    MapGuiAssets;

    MapMkoAssets    m_mkoAssets;
    MapTextureInfos m_textureInfos;
    MapGuiAssets    m_guiScreenAssets;
    MapGuiAssets    m_guiRenderableAssets;

    std::vector<std::string> m_vGuiForRemoval;

public:
    AssetStorage();
    virtual ~AssetStorage();

    static AssetStorage* const get();

    // Mko Objects
    BaseMko*    getMko( const std::string& strId ) const;
    void        add( BaseMko* pMko );
    bool        removeMko( const std::string& strId, bool removeTexture = false );
    void        showLoadedMkoObjects() const;

    // Texture Objects
    TextureInfo getTextureInfo( const std::string& strFilename ) const;
    TextureInfo add( const Texture& texture, const std::string& strFilename );
    bool        removeTextureInfo( const std::string& strFilename );
    bool        removeTextureInfo( unsigned uTextureId );
    void        showLoadedTextureInfo() const;

    // Gui Objects
    GuiElement* getGuiElement( const std::string& strId, GuiType type ) const;
    void        add( GuiElement* pGui, GuiType type );
    bool        removeGuiElement( const std::string& strId, bool removeTextures = false );
    template<typename T>
    bool        removeGuiElement( T* pGui, bool removeTextures = false );
    void        markGuiForRemoval( const std::string& strId );
    void        cleanOrphanedGuiObjects();
    void        showLoadedGuiObjects() const;

private:
    AssetStorage( const AssetStorage& c ); // Not Implemented
    AssetStorage& operator=( const AssetStorage& c ); // Not Implemented

    // Gui Objects
    GuiElement* getGuiElement( const std::string& strId, const MapGuiAssets& guiMap ) const;
    void        add( GuiElement* pGui, MapGuiAssets& guiMap );
    bool        removeGuiElement( const std::string& strId, MapGuiAssets& guiMap, bool removeTextures );
}; // AssetStorage

} // namespace vmk

#endif // ASSET_STORAGE_H

I can also show you the declarations of the BatchManager & ShaderManager classes, but I can not show you the Implementations of them. 我还可以向您显示BatchManagerShaderManager类的声明,但不能向您显示它们的实现

BatchManager.h BatchManager.h

#ifndef BATCH_MANAGER_H
#define BATCH_MANAGER_H

#include "Singleton.h"
#include "CommonStructs.h"

namespace vmk {

class Batch;

class BatchManager sealed : public Singleton {
private:
    std::vector<std::shared_ptr<Batch>> m_vBatches;

    unsigned m_uNumBatches;
    unsigned m_uMaxNumVerticesPerBatch;

public:
    BatchManager( unsigned uNumBatches, unsigned uNumVerticesPerBatch );
    virtual ~BatchManager();

    static BatchManager* const get();

    void render( const std::vector<GuiVertex>& vVertices, const BatchConfig& config, const std::string& strId  );
    void emptyAll();

private:
    BatchManager( const BatchManager& c ); // Not Implemented
    BatchManager& operator=( const BatchManager& c ); // Not Implemented

    void emptyBatch( bool emptyAll, Batch* pBatchToEmpty );
    //void renderBatch( const std::vector<GuiVertex>& vVertices, const BatchConfig& confg );

}; // BatchManager

} // namespace vmk

#endif // BATCH_MANAGER_H

ShaderManager.h ShaderManager.h

#ifndef SHADER_MANAGER_H
#define SHADER_MANAGER_H

#include "Singleton.h"
#include "ShaderProgramSettings.h"

namespace vmk {

class ShaderManager sealed : public Singleton {
private:
    // Number Of Items In enum type Must Match The Number Of Items
    // Stored In s_aShaders And In InfoProgram::aShaderIndex
    enum ShaderType {
        TYPE_VERTEX = 0,
        TYPE_FRAGMENT,
    }; // ShaderType

    struct AttributeVariable{
        unsigned        uLocation;
        AttributeType   eType;
        int             iSize;

        AttributeVariable( AttributeType eTypeIn, unsigned uLocationIn );
    }; // AttributeVariable

    struct UniformVariable{
        unsigned        uLocation;
        UniformType     eType;

        UniformVariable( UniformType eTypeIn, unsigned uLocationIn );
    }; // UniformVariable

    typedef std::unordered_map<Attribute, AttributeVariable> MapAttributes;
    typedef std::unordered_map<Uniform, UniformVariable>     MapUniforms;

    struct InfoProgram{
        unsigned uId;
        std::array<unsigned, 2> aShaderIndex;

        MapAttributes mAttributes;
        MapUniforms   mUniforms;

        InfoProgram();
    }; // InfoProgram

    struct InfoShader{
        unsigned uId;
        std::string strFilename;

        InfoShader( int iOpenglSharedId, std::string strShaderFilename );
    }; // InfoShader

    typedef std::shared_ptr<InfoProgram>    SharedInfoProgram;
    typedef std::shared_ptr<InfoShader>     SharedInfoShader;
    typedef std::vector<SharedInfoProgram>  VectorInfoPrograms;
    typedef std::vector<SharedInfoShader>   VectorInfoShaders;

    VectorInfoPrograms                  m_vPrograms;
    std::array<VectorInfoShaders, 2>    m_avShaders;

    Program m_eEnabledShaderProgram;

    unsigned m_uActiveTextureNumber;

public:
    ShaderManager();
    virtual ~ShaderManager();

    static ShaderManager* const get();

    void create( ShaderProgramSettings& shaderProgramSettings );
    void enable( Program eShaderProgram );
    void enableAttribute( Attribute eShaderAttribute, unsigned strideBytes = 0, unsigned offsetBytes = 0, bool normalize = false ) const;
    void disableAttribute( Attribute eShaderAttribute ) const;
    void setAttribute( Attribute eShaderAttribute, const glm::vec4& v4Value ) const;
    void setUniform( Uniform eShaderUniform, const glm::mat4& m4Matrix ) const;
    void setUniform( Uniform eShaderUniform, const float fValue ) const;
    void setUniform( Uniform eShaderUniform, unsigned uValue ) const;
    void setUniform( Uniform eShaderUniform, bool bValue ) const;
    void setTexture( unsigned uTextureNumber, Uniform eSamplerUniform, int iTextureId );

private:
    ShaderManager( const ShaderManager& c ); // Not Implemented
    ShaderManager& operator=( const ShaderManager& c ); // Not Implemented

    unsigned initializeShader( ShaderType eType, const std::string& strShaderFilename );

    void processAttributes( unsigned uInfoProgramId, Program eShaderProgram, std::vector<ShaderProgramSettings::AttributeInfo>& vAttributes, MapAttributes& mAttributes ) const;
    void processUniforms( unsigned uInforProgramId, Program eShaderProgram, std::vector<ShaderProgramSettings::UniformInfo>& vUniforms, MapUniforms& mUniforms ) const;

    template<typename T>
    void setVertexAttribute( Attribute eShaderAttribute, const T* const pParam, bool bEnable, unsigned strideBytes, unsigned offsetBytes, bool normalize ) const;

    void setVertexAttribute( AttributeVariable attrib, const void* const pVoid, bool bEnable, unsigned strideBytes, unsigned offsetBytes, bool normalize ) const;
    void setVertexAttribute( AttributeVariable attrib, const float* p4Values, bool _x1_, unsigned _x2_, unsigned _x3_, bool _x4_ ) const;

}; // ShaderManager

#include "ShaderManager.inl"

} // namespace vmk

#endif // SHADER_MANAGER_H

As you can see this is quite a complex system of objects and the question that you are asking is a very broad question that can be done in many different ways all depending on your needs. 如您所见,这是一个相当复杂的对象系统,您所要提出的问题是一个非常广泛的问题,可以根据您的需要以多种不同的方式来完成。 I just presented this as to show a single concept of how one might achieve this. 我只是为了说明这一点而展示了一个有关如何实现这一目标的单一概念。

As in the snippets of code above, you can see the different types of containers that are within the AssetStorage class, and then when you look in the BatchManager class you can see the prototypes of the functions to render the vertices which are done by render() and emptyBatch() and emptyAll() . 就像上面的代码片段一样,您可以看到AssetStorage类中不同类型的容器,然后在BatchManager类中查看时,您可以看到用于渲染顶点的函数原型,这些原型由render()emptyBatch()emptyAll()

It is quite unwise to try and have every single "Object" have its own "Render" function. 试图让每个“对象”都有其自己的“渲染”功能是非常不明智的。 Each object should only have to worry about its Attributes & Properties . 每个对象只需要担心其Attributes & Properties It should be the responsibility of the GameEngine to use these sets of classes to know when it is most efficient and time to render said vertices through a Batch Process and then applying the appropriate shading or color techniques. GameEngine的责任是使用这些类集来了解何时最有效,以及何时通过Batch Process来渲染所述顶点,然后应用适当的着色或着色技术。

If every class has a render() function and you want to call all of them with a single command, then you can do this. 如果每个类都有一个render()函数,并且您想用一个命令调用所有这些函数,则可以执行此操作。

class outer
{
public:
    outer(); // Constructor.
    render();

private:
    other_class1 in_class1;
    other_class2 in_class2;
};

outer::render()
{
    in_class1.render();
    in_class2.render();
    // For all other member classes.
}

You can then just call the render function of the outer class outer.render() which calls all of the member classes' render() functions. 然后,您可以调用外部类outer.render()的render函数,该函数调用所有成员类的render()函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM