调用从不兼容类型强制转换的零数据结构的成员函数-未定义
Calling member function of zero data struct which was cast from incompatible type - Undefined?
在不可修改的头文件中声明了一个正向C结构体。我想"实际上"给它添加方便的成员函数。显然,我的首选是扩展结构并将方法添加到派生类中。No-can-do,因为结构本身在头文件中被声明为"forward",所以我得到了错误"error: invalid use of incomplete type…"。如果我尝试用旧结构的单个元素定义一个新结构,我会得到类似的错误。这糟透了。
然而,我想我可以用reinterpret_cast做一些hack来让它工作。它的运行方式是这样的:
//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到类型A的隐式转换,我认为这可以使几乎就像B是A的零数据继承者一样。然而,这显然提出了一个问题:这在c++中是未定义的吗?通常我认为访问非法强制转换结构的元素是未定义的;这说得通。然而,我认为从一种类型到另一种类型的reinterpret_casting,传递该指针,然后再次进行转换,而不做任何非法的事情是可以的。我还认为编译器实现非虚结构成员的方式应该是创建一个函数
B::do_something(B* b, int arg)
,并使用b的适当参数调用它,这就简化为前一种情况,根据我可疑的逻辑,这是可以的。所以我认为在一个结构体上调用。do_something实际上是一个reinterpret_cast a,这是可以的。
然而,这并没有说明c++标准在这个问题上的实际规定。有什么帮助吗?此外,如果有人有关于这将如何实际工作的信息,(即。"每个编译器都接受这个",或者"这只适用于少数编译器"),这也会有所帮助,但稍微不那么有用。
我相信如果您将A*转换为B*,然后再将其转换回A*,那么标准会说您没问题。它们是reinterpret_cast,而不是static_cast。
但是正常的解决方案到底有什么问题呢?
class B
{
private:
A* ptr;
public:
B(A* p) : ptr(p) {}
void do_something(int arg) { do_something_with_A(ptr,arg); }
};
似乎和你的解决方案一样有效,而且更省事。
我不相信这工作,如果你使用static_cast
,因为你不能static_cast
之间的两个完全不相关的类类型。具体来说,如果您有一个类型为A*
的指针,并尝试将其转换为类型为B*
的指针,则static_cast
只有在声明有效的情况下才能成功:
B* ptr(myAPtr);
或者如果B
不是从A
派生的(它不是)。有关这方面的详细信息,请参阅ISO规范5.2.9。如果我们考虑上面的声明,在所有§4中唯一可能应用的转换是§4.10中的转换,其中唯一可能适用的是从基类到派生类的转换(§4.10/3),但这在这里不适用,因为A
和B
不是相关的类型。
唯一的cast你可能能够使用这里是一个reinterpret_cast
,它看起来不像这将工作。特别地,跨类层次的强制转换行为是(§5.2.10/7)
指向对象的指针可以显式地转换为指向不同类型对象的指针。65)除了将"指向T1的指针"类型的右值转换为"指向T2的指针"类型(其中T1和T2是对象类型,并且T2的对齐要求不严格于T1)并返回到其原始类型得到原始指针值外,这种指针转换的结果是未指定的。
因此,如果两个对象有不同的对齐限制,就不能保证任何事情都能正常工作,而且你不能确保这是真的。但假设你可以。不过,在这种情况下,我相信这实际上会正确工作!原因如下。当调用B
对象的成员函数时,规则&5.2.2/1)就会起作用,因为该函数是非虚函数:
[…成员函数调用中调用的函数通常是根据对象表达式的静态类型来选择的。[…)
我们至少调用了正确的函数。那么,this
指针呢?根据&5.2.2/4:
[…如果函数是非静态成员函数,则该函数(9.3.2)的this形参应初始化为指向调用对象的指针,就像通过显式类型转换(5.4)一样进行转换。[…]
在最后一部分中完成的类型转换是从B*
到B*
的标识转换,因为这是所选择的类型。因此,您已经使用适当设置的this
指针调用了正确的函数。好了!最后,当您将reinterpret_cast
返回到原始类型时,根据前面的规则,您将返回A*
对象,并且一切都将按照预期进行。
当然,这只在对象具有相同的对齐要求时才有效,而这并不能保证。因此,你不应该这样做!
希望这对你有帮助!
- 链表,反向函数,数据结构
- 具有结构成员char数组的sscanf
- 哪些存储了不完整类型的 STL 数据结构可以用作类成员?
- 用于对项目进行分组并将单个项目映射到其他组成员的数据结构
- 为什么类成员数据必须是静态的才能被模板化类的模板化结构成员访问
- 是否允许在作为静态数据结构成员的lambda函数中捕获变量
- 在C 中,如何将其作为成员变量构建数据结构
- 如何在构造时声明类对数据结构的哪个成员进行操作
- 指向数据结构成员的指针
- 如何创建一个函数以读/写数据给结构成员
- 当并行线程访问同一数据结构的其他成员时,正确的方法可以在Visual Studio上的OpenMP上并行循环
- 侵入式数据结构中的成员挂钩与基础挂钩
- 动态控制C 数据结构中的成员数量
- 如何将序列化方法添加到作为Windows数据结构的类成员中,以便在C++中与boost序列化一起使用
- 将'std::cin'与数据结构成员结合使用
- 在数据结构中存储成员函数
- 为什么当我尝试访问 CvMat 数据结构成员的第一个元素时,我会得到这个 ^@
- C++:如何将数据插入到结构成员(位于 Vector 中的结构)
- c++数据结构,它根据成员的值自动对对象进行排序
- 在数据结构中保存成员的另一种方法