【问题标题】:C++ Inheritance and how to pass and maintain subclass data through a superclassC++ 继承以及如何通过超类传递和维护子类数据
【发布时间】:2011-07-13 19:43:43
【问题描述】:

好的,我不太清楚如何表达这个问题,也找不到任何我认为真正解决这种情况的重复项。

基本上我有一个超类,它通过子类获取额外的数据。此数据的容器类仅识别超类,并根据超类中的 id 参数调整特征。

实际上,直到最近我才不得不在 c++ 中使用继承,如果这是微不足道的,请原谅我。我的印象是,当我使用超类硬拷贝一堆数据时,可以说子类数据在翻译中丢失了。为了绕过这个限制,我尝试使用类型转换的指针,但是即使在 free() 函数中对指针参数进行类型转换,我现在在尝试释放内存时也会遇到分段错误。

这里是示例代码...

结构

// Super class
struct Vertex {
    __declspec(align(4)) unsigned int vType;              // Identifies the vertex type.

    Vertex(const unsigned int _vType) : vType(_vType) { }
    Vertex(const Vertex &_rV) : vType(_rV.vType) { }      // Copy constructor
    virtual ~Vertex() { }

    unsigned int GetVType() const { return vType; }
};

// Subclass
// Id = 1
struct V_Pos : Vertex {
    __declspec(align(4)) XMFLOAT3 position;

    V_Pos(void) : Vertex(1) { }
    V_Pos(XMFLOAT3 &_rPosition) : Vertex(1), position(_rPosition) { }
    V_Pos(const V_Pos &_rV) : Vertex(_rV), position(_rV.GetPosition()) { } // Copy constructor
    ~V_Pos() { }

    XMFLOAT3 GetPosition() const { return position; }
};

这是我目前复制数据的方式。

// pBuffer is declared as a Vertex* data type
pBuffer = new V_Pos[_bufSize];

if (_pVBuffer->GetVType() == 1)
    for (unsigned int i = 0; i < bufSize; ++i) {
        V_Pos *_temp = (V_Pos*)&_pVBuffer[i];
        pBuffer[i] = *_temp;
    }

这是我目前取消分配数据的方式。

if (pBuffer != 0) {
    delete [] pBuffer;
    pBuffer = 0;
}

这种情况的正确方法是什么?

编辑 1 -

更新了上述代码块,以澄清 knulp 回答下的评论讨论。

【问题讨论】:

  • 为什么要使用子类来更新其超类?
  • @JAB - 我尝试用子类更新超类是为了获取附加的子类数据。整个顶点缓冲区被用作一个 BLOB,它被馈送到一个 COM 对象,然后被遗忘。

标签: c++ inheritance polymorphism


【解决方案1】:

如果你开始混合使用 malloc()/free() 和 C++ 对象的低级内存分配,你会遇到很多麻烦,同时让你的代码几乎不可读。

您应该在适当的构造函数上使用 new 创建一个新对象,该构造函数会自动 1) 分配内存和 2) 初始化结构。要正确释放内存,您应该使用 delete 和析构函数。

您应该使用复制构造函数和赋值运算符进行复制。如果不定义,编译器会自动定义默认的进行按位复制。

为什么要使用类型字段? C++ 具有非常强大的类型特性,因此绕过所有 C++ 机制来定义 vType 几乎没有意义。相反,定义一个基类和两个或多个派生类,然后删除 vtype 字段。

如果您使用干净的 OO 编程,您将从一开始就避免所有这些问题。

【讨论】:

  • 绝对需要在我的 OO 和 C++ 编程上工作。但是,较低级别内存分配的原因是我最终将分配给特定的字节对齐。至于类型字段,我必须根据顶点类型以不同的方式初始化 D3D11 COM 对象,而且我不知道有任何其他方法可以从基类中分辨出它是什么类型的顶点。有没有更好的方法来做到这一点?
  • @Joel - 您不需要使用自定义内存分配器来处理 D3D Verticies。坚持使用新/删除...如有疑问(即使没有疑问),请使用 K.I.S.S.离开。 (“保持简单和愚蠢或面对挫折”)方法。
  • @Zac - 是的,一直在考虑它是多余的,因为我已经在内置的任何 D3D/XNA 优化之上明确地对成员变量进行字节对齐。但是,我确实喜欢至少让所有东西都通过我的内存类来收集性能和分析指标的想法。所以问题是,重载新的操作符让我回到原点还是将内存分配类与构造函数联系起来?...
  • @Joel:重载 new 运算符几乎是微不足道的。我建议你读一些关于这方面的好书。您可以从这个简单的教程开始:cprogramming.com/tutorial/operator_new.html,然后再深入。 Bruce Eckel “Thinking in C++”是免费提供的,并且有很好的解释。但是,正如@Zac 所说,保持简单:如果您想收集统计信息,我建议您在构造函数和析构函数中进行。
  • 好的,开始将代码更改为我们讨论的解决方案,但我仍然对如何正确复制缓冲区感到困惑。一旦将派生成员字段复制到容器类的缓冲区,使用取消引用的类型转换派生类指针(这是一个满嘴的)仍然会给我派生成员字段的垃圾数据。 C++ 的多态机制不应该处理这个问题,还是我需要以特定方式为两个类重载赋值运算符?或者试图让这样的类足够灵活以处理所有可能的不同顶点类型是一个糟糕的设计决策?
【解决方案2】:

您的基类需要有一个虚拟析构函数。这将允许您安全地删除带有基类指针的派生类。

【讨论】:

    【解决方案3】:

    不是这样的!使用复制构造函数。

        // Super class
    struct Vertex {
        __declspec(align(4)) unsigned int vType; // Identifies the vertex type.
        Vertex(const unsigned int _vType) : vType(_vType) { }
    
        unsigned int GetVType() const { return vType; }
    
        Vertex(const Vertex& v) : vType(v.vType) {}
    };
    
    // Subclass
    // Id = 1
    struct V_Pos : Vertex {
        __declspec(align(4)) XMFLOAT3 position;
    
        V_Pos(void) : Vertex(1) { }
        V_Pos(XMFLOAT3 &_rPosition) : Vertex(1), position(_rPosition) { }
    
        V_Pos(const V_Pos& v) : Vertex(v) { 
           position[0] = v.position[0];
           position[1] = v.position[1];
           position[2] = v.position[2];
        }
    };
    

    更好的是,使用 vecotr 而不是 XMFLOAT3;

    在堆上创建一个副本: V_Pos 原始(...); V_Pos * copyPtr = new V_Pos(original);

    【讨论】:

      猜你喜欢
      • 2014-12-25
      • 2018-05-25
      • 1970-01-01
      • 2016-05-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-03
      • 1970-01-01
      相关资源
      最近更新 更多