在这种情况下可以转换一个指向成员变量的指针吗?
我最近一直在刷新/更新我的 C++ 知识,并且了解严格别名使我对将一种类型的指针转换为另一种类型有点谨慎。我知道下面的代码示例在我的编译器上实际工作,但我想确保它符合当前标准:
#include <iostream>
using namespace std;
class MyBase {
public:
virtual void DoSomething() = 0;
};
class MyDerived1 : public MyBase {
public:
virtual void DoSomething() {
cout << "I'm #1" << endl;
}
};
class MyDerived2 : public MyBase {
public:
virtual void DoSomething() {
cout << "I'm #2" << endl;
}
};
template <typename Base, typename Member1, typename Member2>
struct Tuple {
public:
Base* Get(int i) {
return &(this->*(lookupTable[i]));
}
private:
Member1 member1;
Member2 member2;
static Base Tuple::* const lookupTable[2];
};
template <typename Base, typename Member1, typename Member2>
Base Tuple<Base, Member1, Member2>::* const Tuple<Base, Member1, Member2>::lookupTable[2] = {
reinterpret_cast<Base Tuple<Base, Member1, Member2>::*>(&Tuple::member1),
reinterpret_cast<Base Tuple<Base, Member1, Member2>::*>(&Tuple::member2)
};
int main() {
Tuple<MyBase, MyDerived1, MyDerived2> tuple;
tuple.Get(0)->DoSomething();
tuple.Get(1)->DoSomething();
return 0;
}
本质上,这个简单的元组包含一对元素,每个元素都应该派生自一个公共基类。 Get 函数将 Base*
返回给给定索引表示的成员。
我想知道的关键部分是reinterpret_casts。我知道从 Derived Struct::*
到 Base Struct::*
的转换通常是禁忌,但在这种情况下我只使用指向成员变量的指针来获取指向对象的指针。 (我不会尝试复制派生对象,就好像它是基对象一样,也不会将基对象填充到派生对象的内存中。)这在 G++ 上按预期工作,我只是想确保我不是任何兼容的编译器都会因为这样做而受到影响。
I've been refreshing/updating my knowledge of C++ lately, and learning about strict aliasing has made me a bit wary of casting pointers of one type to another. I know that this following code sample works in practice on my compiler, but I want to make sure that it conforms to current standards:
#include <iostream>
using namespace std;
class MyBase {
public:
virtual void DoSomething() = 0;
};
class MyDerived1 : public MyBase {
public:
virtual void DoSomething() {
cout << "I'm #1" << endl;
}
};
class MyDerived2 : public MyBase {
public:
virtual void DoSomething() {
cout << "I'm #2" << endl;
}
};
template <typename Base, typename Member1, typename Member2>
struct Tuple {
public:
Base* Get(int i) {
return &(this->*(lookupTable[i]));
}
private:
Member1 member1;
Member2 member2;
static Base Tuple::* const lookupTable[2];
};
template <typename Base, typename Member1, typename Member2>
Base Tuple<Base, Member1, Member2>::* const Tuple<Base, Member1, Member2>::lookupTable[2] = {
reinterpret_cast<Base Tuple<Base, Member1, Member2>::*>(&Tuple::member1),
reinterpret_cast<Base Tuple<Base, Member1, Member2>::*>(&Tuple::member2)
};
int main() {
Tuple<MyBase, MyDerived1, MyDerived2> tuple;
tuple.Get(0)->DoSomething();
tuple.Get(1)->DoSomething();
return 0;
}
Essentially, this simple tuple contains a pair of elements, each of which should derive from a common base class. The Get function returns a Base*
to the member that the given index represents.
The key part that I'm wondering about is the reinterpret_casts. I know that casting from Derived Struct::*
to Base Struct::*
is generally a no-no, but in this case I only use the pointers-to-member-variable to get a pointer to the object. (I don't try to copy a derived object as though it were a base object, nor stuff a base object into a derived object's memory.) This works as intended on G++, and I just want to be sure that I'm not going to get bitten by any compliant compilers for doing this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
你不应该在那里使用reinterpret_cast。实际上,当您的目标是可移植性时,您不应该在任何地方提及reinterpret_cast 的使用。根据定义,reinterpret_cast 具有特定于平台的结果。
要将指向基类的指针转换为派生类的指针,请使用dynamic_cast,当指向的对象不属于派生类时,它将返回NULL。如果您绝对确定该类是正确的,那么您可以使用 static_cast。
You should not use reinterpret_cast there. Actually you should not mention usage of reinterpret_cast anywhere where your goal is portability. reinterpret_cast is by definition something that has platform-specific results.
For casting a pointer to base into pointer of derived class use dynamic_cast, it will return NULL when the object pointed is not of derived class. If you are absolutely sure that the class is correct then you may use static_cast.
使用
reinterpret_cast
几乎是不可移植的。最重要的是,对成员指针强制转换的唯一有效使用是从Type Derived::*
到Type Base::*
的隐式强制转换> 并仔细使用从Type Base::*
到Type Derived::*
的static_cast
。由于您想要更改成员的类型,而不是包含成员的对象的类型,因此这两者都不是。将微小函数而不是指向成员的指针放入该数组中怎么样?以下代码经过测试,应该是完全可移植的。
Use of
reinterpret_cast
is almost never portable. On top of that, the only valid use of pointer to member casts are the implicit cast fromType Derived::*
toType Base::*
and careful uses of thestatic_cast
fromType Base::*
toType Derived::*
. Since you want to change the type of the member, not the type of the object containing members, this is neither of those.How about putting tiny functions in that array instead of pointers to members? The following code is tested and should be entirely portable.
编辑:参考标准。如果我没看错的话,因为您没有遇到任何异常,所以您所做的事情是未指定的,因此可能会或可能不会在任何特定编译器上工作。相关成员的类型没有任何例外。
从 5.2.10/9 (reinterpret_cast) 开始:
EDIT: Reference from standard. If I'm reading it right, as you don't meet either of the exceptions, what you've done is unspecified and so may or may not work on any particular compiler. There aren't any exceptions for the type of the member being related.
From 5.2.10/9 (reinterpret_cast):
C 风格的cast 总是比reinterpret_cast 更好。
如果C风格的转换工作,它是独立的有效平台。
始终避免reinterpret_cast。
编辑
我的意思是,使用reinterpret_cast你可能会指向错误的内存地址,C风格的转换处理所有与平台相关的问题,例如ABI,内存对齐,指针大小等。
编辑
受评论者的启发,我阅读了 ISO/IEC 14882:2003 第 5.2.10 节“Reinterpret_cast”。
当然,我的理解是有限的,但让我想起为什么我首先讨厌reinterpret_cast。
我认为,reinterpret_cast缺乏或对继承层次结构的认识非常有限。
如果强制转换操作数是具有复杂继承层次结构的类的实例指针(例如ATL/COM类),则一个reinterpret_cast足以杀死您的进程并产生难以理解的错误。
我们可以使用 C 风格的强制转换,但对后面的实际强制转换操作有模糊的了解。但我们必须真正了解确切的细节才能安全地使用reinterpret_cast。
C style cast is always better than reinterpret_cast.
If C style cast work, it is valid platform independently.
Always avoid reinterpret_cast.
EDITED
I mean, with reinterpret_cast you could point wrong memory address, C style cast handle all the platform related issues such as ABI, memory align, pointer size, etc.
EDITED
By the inspiration of commentators, I've read ISO/IEC 14882:2003 section 5.2.10 "Reinterpret_cast".
Of course my comprehension is limited, but it strikes me to remember why I hated reinterpret_cast in the first place.
I think, reinterpret_cast is lack of or has very limited awareness of inheritance hierarchy.
If cast operand is a instance pointer of class which has complicated inheritance hierarchy (such as ATL/COM classes), one reinterpret_cast is enough to kill you process with incomprehensible errors.
We can use C style cast with vague knowledge of actual cast operation behind. But we must really know exact detail to use reinterpret_cast safely.