【问题标题】:Storing subclasses in superclass vector在超类向量中存储子类
【发布时间】:2012-08-24 01:57:55
【问题描述】:

我正在尝试为 AccidentalNoise 库构建一个音序器,用户可以在其中生成描述各种类型噪声层的 XML 文件,并获得结果。我很难理解继承在 C++ 中是如何工作的。

不幸的是,并非所有子类(在这种情况下为 CImplicitSphere)的方法都在超类(CImplicitModuleBase)中定义,因此我没有成功立即初始化向量值(CImplicitSphere.setCenter() 就是一个很好的例子)。这是我到目前为止所得到的:

std::vector<anl::CImplicitModuleBase *> layers;

anl::CImplicitSphere tmp;

tmp.setCenter(0.0,0.0,0.0,0.0,0.0,0.0);

layers.push_back(&tmp);

value = layers.back()->get(0.0,0.0,0.0);

但是我遇到了一个“称为纯虚拟方法”的错误——这就是我卡住的地方——我需要进行类型转换吗?对此进行了一些讨论 - 但似乎表明这是一个坏主意。

有没有更好的方法来构造我的代码,以便我可以直接在层向量中初始化 CImplicitSphere,并在我执行时指向子类方法?

完整来源:

void ScalarTerrain::setupAccidentalNoise() {
printf("Making an array of noise functions\n");
std::vector<anl::CImplicitModuleBase *> layers;

try {
    printf("Getting data for next layer\n");
    pugi::xml_node layer = terrainData.child("layer");

    if(strcmp(layer.attribute("type").value(), "sphere") == 0) {
        printf("Layer is a sphere building a temp layer\n");
        anl::CImplicitSphere tmp;

        tmp.setCenter(
            layer.child("center").attribute("x").as_double(),
            layer.child("center").attribute("y").as_double(),
            layer.child("center").attribute("z").as_double(),
            layer.child("center").attribute("u").as_double(),
            layer.child("center").attribute("v").as_double(),
            layer.child("center").attribute("w").as_double()
        );

        layers.push_back(&tmp);
    }
     else {
        printf("Layer type not found\n");
    }


} catch (char * exception) {
    printf("Exception raised: %s\n", exception);
}
try {
    for(int z = 0; z < z_chunk; z++) {
        for(int y = 0; y < y_chunk; y++) {
            for(int x = 0; x < x_chunk; x++) {
                value = layers.back()->get(
                    (double) x/x_chunk * 2, 
                    (double) y/y_chunk * 2, 
                    (double) z/z_chunk * 2
                );

                tc.values[x][y][z] = value;

                if(value < -0.5) tc.materials[x][y][z] = 0;
                else if (value < 0) tc.materials[x][y][z] = 1;
                else if (value < 0.5) tc.materials[x][y][z] = 2;
                else tc.materials[x][y][z] = 3;
            }
        }
    }
} catch (char * exception) {
    printf("Exception raised: %s\n", exception);
}
}

【问题讨论】:

  • 矢量部分不是很重要——任何对象集合都可以。
  • 根据online docs,派生类(CImplicitSphere) 不提供纯虚拟get 方法的实现。为什么?我不知道,我不使用图书馆。另外 - 您正在将自动存储变量的地址添加到向量中。这是你的意图吗?
  • 我不知道 - 我来自高级语言的背景,而深入研究 C++ 是我学习 C++ 的唯一途径。
  • 你能发布完整的源文件吗?
  • CImplicitSphere 确实实现了 get() 似乎文档只显示了独特的方法。

标签: c++ vector subclass superclass


【解决方案1】:

这似乎有效,而且并不丑陋:

void ScalarTerrain::setupAccidentalNoise() {
printf("Making an array of noise functions\n");
std::vector<anl::CImplicitModuleBase *> layers;
anl::CImplicitModuleBase * tmp;


//anl::CImplicitSphere thisLayer;

try {
    printf("Getting data for next layer\n");
    pugi::xml_node layer = terrainData.child("layer");

    if(strcmp(layer.attribute("type").value(), "sphere") == 0) {
        printf("Layer is a sphere building a temp layer\n");
        tmp = new anl::CImplicitSphere();

        dynamic_cast<anl::CImplicitSphere*>(tmp)->setCenter(
            layer.child("center").attribute("x").as_double(),
            layer.child("center").attribute("y").as_double(),
            layer.child("center").attribute("z").as_double(),
            layer.child("center").attribute("u").as_double(),
            layer.child("center").attribute("v").as_double(),
            layer.child("center").attribute("w").as_double()
        );

        layers.push_back(tmp);
    }
     else {
        printf("Layer type not found\n");
    }


} catch (char * exception) {
    printf("Exception raised: %s\n", exception);
}
try {
    printf("Iterating through blocks\n");

    for(int z = 0; z < z_chunk; z++) {
        for(int y = 0; y < y_chunk; y++) {
            for(int x = 0; x < x_chunk; x++) {
                printf("getting block value at %d %d %d\n",x,y,z);

                value = layers.back()->get(
                    (double) x/x_chunk * 2, 
                    (double) y/y_chunk * 2, 
                    (double) z/z_chunk * 2
                );

                tc.values[x][y][z] = value;

                if(value < -0.5) tc.materials[x][y][z] = 0;
                else if (value < 0) tc.materials[x][y][z] = 1;
                else if (value < 0.5) tc.materials[x][y][z] = 2;
                else tc.materials[x][y][z] = 3;
            }
        }
    }
} catch (char * exception) {
    printf("Exception raised: %s\n", exception);
}
}

这是“正确”的做事方式还是我离题了?

【讨论】:

  • 如果您将tmp 设为CImplicitSphere* 而不是CImplicitModuleBase*,您将不必为了setCenter 而使用dynamic_cast,以及指向基类的指针向量还是会接受的。
  • 这只是脚本的开始——我的想法是循环一个 if/else 链,在 tmp 中创建一个新对象(可能是 CImplicitSphere,可能是 CImplicitFractal,可能是 CImplicitBasisFunction 等)配置它,可能引用向量中的前一个(看起来它可能需要是一张地图)并将其放到集合中。在 tmp 上不断地重新制作 CImplicitModuleBase 对象会不会给我带来麻烦?
猜你喜欢
  • 1970-01-01
  • 2020-11-14
  • 2014-09-10
  • 2021-11-09
  • 2012-12-15
  • 2021-10-04
  • 1970-01-01
  • 2017-08-30
  • 1970-01-01
相关资源
最近更新 更多