从基类指针获取模板派生类的值

Getting template derive class's value from base class pointer

本文关键字:派生 基类 指针 获取      更新时间:2023-10-16

我有一个工具允许用户编辑glsl的统一变量值,我需要将所有数据存储在std::vector中。

由于所有变量的值都有不同的变量类型(vec2, vec3, vec4, mat2...等),将它们存储在单个容器中是一个挑战。我决定采用这种方法

class BaseData
{
    public:
};
template <typename T>
class Data: public BaseData
{
public:
    Data(TypeEnum enumType, T valueIN): value(valueIN), type(enumType)
    {
    }
    T GetValue()
    {
        return value; 
    }
    TypeEnum GetType()
    {
        return type;
    }
private:
    T value;
    TypeEnum type;
};
class Material
{
    Material(std::vector<Base*> valueVec)
    {
        for(auto i : valueVec)
        { 
            switch(i->GetType())
            {
                case BaseColor:
                    SetBaseColor(i->GetValue());//need something like this
                    break;
                case BaseTexture:
                    SetBaseTexture(i->GetValue());//need something like this
                    break;
                case EmissionColor:
                    SetEmissionFactor(i->GetValue());//need something like this
                    break;
                case EmissionTexture:
                    SetEmissionTexture(i->GetValue());//need something like this
                    break;
                case Material_nProps_NormalTexture:
                    SetNormalMap(i->GetValue());//need something like this
            } 
        }
    }
}
int main()
{
    std::vector<BaseData*> uniformValue;
    uniformValue.push_back(new Data(BaseColor, glm::vec4(1,2,3,4)));
    uniformValue.push_back(new Data(BaseTexture, 0));
    uniformValue.push_back(new Data(EmissionColor, glm::vec3(1,1,1)));    
    uniformValue.push_back(new Data(BaseTexture, 1));
    Material PBR(uniformValue);
}

但问题是,现在如何从基指针获取而不将其强制转换为正确的派生类型指针?

如果不想强制转换,可以使用命令模式,其中每个 GLSL 属性类接收指向 Material 对象的指针并执行相应的操作。每个命令都需要访问材质的某些内部结构。下面的代码对此进行了说明。(请注意,一切都是公开的,只是为了简单起见)。

struct Material; // forward declaration
struct GlslPropertyBase {
    virtual ~GlslPropertyBase() {}
    virtual void Execute(Material* m) = 0;
};
struct Material {
    void SetBaseColor(Vec3 col) { /* Do something */ }
    void SetBaseTexture(GLuint uid) { /* Do something */ }
    Material(std::vector<GlslPropertyBase*> properties) {
        for (GlslPropertyBase* property : properties)
            property->Execute(this);
    }
};
struct GlSlBaseColor : GlslPropertyBase {
    Vec3 color;
    GlSlBaseColor(float r, float g, float b) : color(r, g, b) {}
    void Execute(Material* m) { m->SetBaseColor(color); }
};
struct GlSlBaseTexture : GlslPropertyBase {
    GLuint uid;
    GlSlBaseTexture(GLuint uid) : uid(uid) {}
    void Execute(Material* m) { m->SetBaseTexture(uid); }
};
int main() {
    std::vector<GlslPropertyBase*> properties;
    properties.push_back(new GlSlBaseColor(1, 2, 3));
    properties.push_back(new GlSlBaseTexture(1));
    Material PBR(properties);
    // delete heap objects...
}

这只是一种简单的方法(和实现),用于处理存储在单个向量中的异构 glsl 属性,而无需强制转换,这可能是@francesco在他的答案末尾建议的。