我很好奇将指针转换为派生类和基类实际上是如何工作的。这是一个例子:
struct A {};
struct B : A {};
// Boxing a pointer to an instance of B
void* p = new B();
现在,假设我想通过指针 p 访问 A 的可能成员或方法。
A* a1 = (A*)p;
A* a2 = (A*)((B*)p);
哪一个是正确的?有什么区别吗?
你能告诉我在哪里可以获得关于这个主题的更多信息吗?
我很好奇将指针转换为派生类和基类实际上是如何工作的。这是一个例子:
struct A {};
struct B : A {};
// Boxing a pointer to an instance of B
void* p = new B();
现在,假设我想通过指针 p 访问 A 的可能成员或方法。
A* a1 = (A*)p;
A* a2 = (A*)((B*)p);
哪一个是正确的?有什么区别吗?
你能告诉我在哪里可以获得关于这个主题的更多信息吗?
在这种情况下,实践上没有区别。
但是如果有多重继承可能会有区别:
#include <cstdio>
struct A { int x; };
struct B { int y; };
struct C : B, A {};
int main() {
void* c = new C();
printf("%p\n", c); // 0x1000
printf("%p\n", (A*) c); // 0x1000
printf("%p\n", (A*) ((C*) c)); // 0x1004
return 0;
}
或者子类有虚拟方法但父类没有[1],包括使用虚拟继承[2]。
就标准而言,由于 OP 使用 C 风格转换,在这种情况下相当于static_cast
.
转换序列B*
→ void*
→ B*
→A*
是有效的,其中前两个转换将返回与 §5.2.9[expr.static.cast]/13 要求的相同的指针,最后一个转换用作指针转换 §4.10[conv .ptr]/3。
但是,强制转换序列B*
→ void*
→A*
实际上会给出未定义的结果,因为在 §5.2.9/13 ☺ 中没有定义结果。
[1]:
#include <cstdio>
struct A { int x; };
struct C : A { virtual void g() {} };
int main() {
void* c = new C();
printf("%p\n", c); // 0x1000
printf("%p\n", (A*) c); // 0x1000
printf("%p\n", (A*) ((C*) c)); // 0x1008
return 0;
}
[2]:
#include <cstdio>
struct A { int x; };
struct C : virtual A {};
int main() {
void* c = new C();
printf("%p\n", c); // 0x1000
printf("%p\n", (A*) c); // 0x1000
printf("%p\n", (A*) ((C*) c)); // 0x1008
return 0;
}