2011-10-14 21 views
9

比方说,我有两个不同的类,均表示2D中像下面的相同的内部的方式坐标数据:给定两个类是相同的,并且上述功能在两个相同类的指针之间进行转换的安全性?

class LibA_Vertex{ 
    public: 
    // ... constructors and various methods, operator overloads 
    float x, y 
}; 

class LibB_Vertex{ 
    public: 
    // ... same usage and internal data as LibA, but with different methods 
    float x, y 
}; 


void foobar(){ 
    LibA_Vertex * verticesA = new LibA_Vertex[1000]; 
    verticesA[50].y = 9; 
    LibB_Vertex * verticesB = reinterpret_cast<LibB_Vertex*>(vertexA); 
    print(verticesB[50].y); // should output a "9" 
}; 

,我可以可靠地在该指针转换计数在每种情况下按预期工作? (背景是,我需要一个简单的方法来交换具有相同顶点类的两个独立库之间的顶点数组,并且我希望避免不必要的复制数组)。

回答

13

C++ 11增加了一个名为的布局兼容的概念,适用于此。

两个标准布局结构(第9节)类型布局兼容如果它们具有相同数量的非静态数据成员和相应的非静态数据成员(在声明顺序)的具有版式兼容类型(3.9)。

其中

标准布局类是一类:

  • 具有类型非标准布局类的没有非静态数据成员(或这种类型的阵列)或参考,
  • 没有虚拟功能(10.3)并且没有虚拟基类(10.1),
  • 对于所有非静态数据m(第11条)具有相同的访问控制余烬,
  • 没有非标准布局基类,
  • 要么在派生类最多的情况下没有非静态数据成员,要么至少有一个基类有非静态数据成员,或者没有基类非静态数据成员,并且
  • 没有与第一个非静态数据成员相同类型的基类。

标准布局结构类键struct类密钥class限定的标准布局类

标准布局联合类密钥union限定的标准布局类

最后

指针到CV-合格和布局兼容 类型的CV-不合格的版本(3.9.3)应具有相同的值表示和对准要求(3.11)。

这保证reinterpret_cast可以将指针转换为指向任何布局兼容类型的指针。

+3

做这些转换的另一个明确的方法是使用具有共同初始序列的联合(如§9.2/ 19所允许的)。 – Mankarse

+0

哦!那么,C++ 11来拯救。我只是希望这是VS2010决定在樱桃采摘标准时添加的东西。 –

+1

@Clairvoire:这是在实践中始终有效的事情之一,即使被正式禁止。我不指望任何编译器编写者必须“添加”支持。 –

1

我会把这个转换放到一个类中(这样如果你需要改变平台或者其他的东西,它至少在一个地方被本地化),但是它应该是可能的。

您也可以使用reinterpret_cast而不是static_cast

+0

你是对的,我的错!更正了问题 –

1

理论上这是一个未定义的行为。但是,它可能适用于某些系统/平台。

我建议你应该尝试 2班合并为1即

class Lib_Vertex{ 
// data (which is exactly same for both classes) 
public: 
// methods for LibA_Vertex 
// methods for LibB_Vertex 
}; 

添加方法为class不会影响它的大小。你可能不得不改变你的设计,但它是值得的。

+0

通常,我也会使用类似的东西。我仍然需要制作阵列的副本。一个库(2D物理库)使用它的内部顶点类返回整个顶点数组,然后我需要将其馈入另一个库(2D渲染库),该库接受其内部顶点类的数组。 –

0

从技术上讲,这是未定义的行为。实际上,如果使用相同的编译器来编译这两个类,那么如果字段按照相同的顺序声明,具有相同的类型和相同的访问级别,则它们将在内存中具有相同的布局。

相关问题