C++ 调用从不兼容类型强制转换的零数据结构的成员函数-未定义?

C++ 调用从不兼容类型强制转换的零数据结构的成员函数-未定义?,c++,struct,reinterpret-cast,C++,Struct,Reinterpret Cast,在不可修改的标头中声明了一个正向C结构。我想“虚拟地”为它添加方便的成员函数。显然,我的第一个选择是扩展结构并将方法添加到派生类中。不行,因为结构本身在头中声明为“forward”,所以我得到错误“error:invalid use of complete type…”。如果尝试使用旧结构的单个元素定义新结构,则会出现类似的错误。这太糟糕了 然而,我想我可以用reinterpret_cast做一些黑客操作,让它无论如何都能工作。这样做的方式是: //defined in header struc

在不可修改的标头中声明了一个正向C结构。我想“虚拟地”为它添加方便的成员函数。显然,我的第一个选择是扩展结构并将方法添加到派生类中。不行,因为结构本身在头中声明为“forward”,所以我得到错误“error:invalid use of complete type…”。如果尝试使用旧结构的单个元素定义新结构,则会出现类似的错误。这太糟糕了

然而,我想我可以用reinterpret_cast做一些黑客操作,让它无论如何都能工作。这样做的方式是:

//defined in header
struct A forward;
void do_something_with_A(A* a, int arg);

//defined in my wrapper
struct B {
  B* wrap(A* a) {return reinterpret_cast<B*>(a); }
  void do_something(int arg) {do_something_with_A(reinterpret_cast<A*>(this),arg); }
}
用适当的参数B来调用它,然后就简化到前面的例子,根据我可疑的逻辑,这是可以的。所以我想在一个实际上是重新解释的结构上调用。dou__,some,dou_,some,dou,some,dou,some,dou,dou,dou,dou,dou,dou,dou,dou,dou,dou,dou,dou


然而,这并没有说明C++标准在这个问题上的实际含义。有什么帮助吗?此外,如果有人知道这在实践中的效果如何,(例如,“每一个编译器都接受这一点”,或者“这只适用于少数编译器”),这也会有帮助,但效果稍差。

我相信,如果你将a*转换为B*再转换回a*,那么标准会说你没问题。这些将是重新解释的类型转换,尽管不是静态类型转换

但正常的解决方案到底有什么问题

class B
{
private:
  A* ptr;
public:
  B(A* p) : ptr(p) {}
  void do_something(int arg) { do_something_with_A(ptr,arg); }
};

似乎和你的解决方案一样有效,而且不那么麻烦。

我相信如果你把A*转换成B*再转换成A*,那么标准会说你没问题。这些将是重新解释的类型转换,尽管不是静态类型转换

但正常的解决方案到底有什么问题

class B
{
private:
  A* ptr;
public:
  B(A* p) : ptr(p) {}
  void do_something(int arg) { do_something_with_A(ptr,arg); }
};

似乎与您的解决方案一样高效,而且不太麻烦。

如果您使用
静态\u cast
,我认为这不起作用,因为您无法在两个完全不相关的类类型之间进行
静态\u cast
。具体来说,如果您有一个
a*
类型的指针,并尝试将其转换为
B*
类型的指针,则只有在该声明有效时,
静态转换才会成功:

B* ptr(myAPtr);
或者如果
B
是从
A
非虚拟派生的(它不是)。有关本规范的详细信息,请参见ISO规范§5.2.9。如果我们考虑上面的声明,在第4节中所应用的唯一可能的转换是在第4.10节中的那些,并且那些唯一适用的是从基转换到派生类(4.10/3),但是这里不适用,因为<代码> a < /> >和<代码> b>代码>不是相关的类型。 在这里,您可能可以使用的唯一强制转换是
重新解释强制转换
,看起来这也行不通。特别是,跨类层次结构的强制转换行为是(§5.2.10/7)

指向对象的指针可以显式转换为指向不同类型对象的指针。65)除了将类型为“指向T1的指针”的右值转换为类型为“指向T2的指针”(其中T1和T2是对象类型,T2的对齐要求不比T1严格)返回到其原始类型将产生原始指针值,此类指针转换的结果未指定

因此,如果两个对象具有不同的对齐限制,则无法立即保证任何东西都能正常工作,并且您无法确保这是真的。但是假设你可以。不过,在这种情况下,我相信这实际上是正确的!理由是这样的。当您调用
B
对象的成员函数时,规则&5.2.2/1)将生效,并指出,由于函数是非虚拟的:

[…]成员函数调用中调用的函数通常根据对象表达式的静态类型进行选择。[……]

好的,我们至少调用了正确的函数。现在,这个
指针怎么样?那么根据&5.2.2/4:

[…]如果函数是非静态成员函数,则函数(9.3.2)的“this”参数应使用指向调用对象的指针进行初始化,如同通过显式类型转换(5.4)进行转换一样。[……]

上一部分中完成的类型转换是从a
B*
到a
B*
的身份转换,因为这是所选类型。因此,您调用了正确的函数,并适当地设置了
这个
指针。美好的最后,当您执行
重新解释\u cast
返回原始类型时,根据前面的规则,您将返回
a*
对象,一切都将按预期进行

当然,这仅在对象具有相同对齐要求时有效,并且无法保证。因此,你不应该这样做


希望这有帮助

如果您使用的是
static\u cast
,我认为这不起作用,因为您不能在两个完全不相关的类类型之间进行
static\u cast
。具体来说,如果您有一个
a*
类型的指针,并尝试将其转换为
B*
类型的指针,则只有在该声明有效时,
静态转换才会成功:

B* ptr(myAPtr);
或者如果
B
是从
A
非虚拟派生的(它不是)。有关本规范的详细信息,请参见ISO规范§5.2.9。如果我们考虑上面的声明,在第4节中所应用的唯一可能的转换是在第4.10节中的那些,并且那些唯一适用的是从基转换到派生类(4.10/3),但是这里不适用,因为<代码> a < /> >和<代码> b>代码>不是相关的类型。 在这里,您可能可以使用的唯一强制转换是
重新解释强制转换
,看起来这也行不通。特别是铸件的性能