void* 是否保留继承信息?
Does void* reserve inheritance information?
是否可以void*
保留类型信息?
我试图通过将 B* b
转换为 void* v
来让它忘记真实类型 (B*
),但它似乎知道它的来源。
这对我来说是好运,但我不知道为什么。
这是一个简化的代码(full demo) :-
#include <iostream>
#include <memory>
using namespace std;
class B{public: int ib=1;};
class C:public B{public: int ic=2;};
int main() {
B* b=new C();
void* v=b; //<- now you forget it!
C* c=static_cast<C*>(v);
std::cout<<c->ib<<" "<<c->ic<<std::endl; //print 1 and 2 correct (it should not)
return 0;
}
本以为c
指向B*
的地址(一个错误的地址),但似乎知道v
是B*
并正确投射。
问题
为什么有效? void*
真的记得类型吗?
它能走多远"remember"?
背景
我正在尝试创建一个 void*
摘要 class here,但很惊讶它的工作原理。
我想确保这是预期的标准行为。
编辑:抱歉新手问题。
现在,我意识到我误解了 void*
.
未定义的行为是未定义。这意味着您可能 可能 ,无论如何都会得到 "right answer"。
在这种特殊情况下,您的编译器布局完全有可能组织 C
,使得 C
及其基数 class B
具有相同的地址。因此,如果您假装一个以未定义的方式指向另一个,您将获得正确的行为。
今天。明天会发生什么是猜测。
这不是你可以依赖的东西。这只是一个 "fortunate" 偶然事件。
It's a pointer to C, then a pointer to B, then a pointer to void, then a pointer to C again. All perfectly legal conversions.
不,他们不是。
它是指向 C
的指针,然后是指向 B
的指针。然后就变成了void*
。但标准非常明确:如果将指针转换为 void*
, 唯一合法的转换 是将其转换为指向 的指针type 从中投射出来的。所以如果你从 B*
转换成 void*
,唯一合法的转换是回到 B*
.
不是派生自 B
的类型。
C++17 将 "the exact type" 变为 "a pointer interconvertible type"。但是基础和派生 classes 是 not pointer-interconvertible,所以它仍然是 UB。
(Nicol 是正确的,我的回答是入门级的,没有涉及语言律师,不过,你应该会发现它与你在现实中的观察充分吻合。)
I expected c to point to the address of B*
确实如此。
(a wrong address)
不,这是正确的地址。
but it seems to know that v is B* and correctly cast.
它知道每个 C
都有一个 B
碱基。因为那是 C
的定义方式。
所以 C*
指向一个内存区域,其中包含一些 B
内容,然后是一些 C
内容。
你的 void*
什么都不记得了;所有这些 "intelligence" 都在 B
和 C
.
的定义中
是否可以void*
保留类型信息?
我试图通过将 B* b
转换为 void* v
来让它忘记真实类型 (B*
),但它似乎知道它的来源。
这对我来说是好运,但我不知道为什么。
这是一个简化的代码(full demo) :-
#include <iostream>
#include <memory>
using namespace std;
class B{public: int ib=1;};
class C:public B{public: int ic=2;};
int main() {
B* b=new C();
void* v=b; //<- now you forget it!
C* c=static_cast<C*>(v);
std::cout<<c->ib<<" "<<c->ic<<std::endl; //print 1 and 2 correct (it should not)
return 0;
}
本以为c
指向B*
的地址(一个错误的地址),但似乎知道v
是B*
并正确投射。
问题
为什么有效? void*
真的记得类型吗?
它能走多远"remember"?
背景
我正在尝试创建一个 void*
摘要 class here,但很惊讶它的工作原理。
我想确保这是预期的标准行为。
编辑:抱歉新手问题。
现在,我意识到我误解了 void*
.
未定义的行为是未定义。这意味着您可能 可能 ,无论如何都会得到 "right answer"。
在这种特殊情况下,您的编译器布局完全有可能组织 C
,使得 C
及其基数 class B
具有相同的地址。因此,如果您假装一个以未定义的方式指向另一个,您将获得正确的行为。
今天。明天会发生什么是猜测。
这不是你可以依赖的东西。这只是一个 "fortunate" 偶然事件。
It's a pointer to C, then a pointer to B, then a pointer to void, then a pointer to C again. All perfectly legal conversions.
不,他们不是。
它是指向 C
的指针,然后是指向 B
的指针。然后就变成了void*
。但标准非常明确:如果将指针转换为 void*
, 唯一合法的转换 是将其转换为指向 的指针type 从中投射出来的。所以如果你从 B*
转换成 void*
,唯一合法的转换是回到 B*
.
不是派生自 B
的类型。
C++17 将 "the exact type" 变为 "a pointer interconvertible type"。但是基础和派生 classes 是 not pointer-interconvertible,所以它仍然是 UB。
(Nicol 是正确的,我的回答是入门级的,没有涉及语言律师,不过,你应该会发现它与你在现实中的观察充分吻合。)
I expected c to point to the address of B*
确实如此。
(a wrong address)
不,这是正确的地址。
but it seems to know that v is B* and correctly cast.
它知道每个 C
都有一个 B
碱基。因为那是 C
的定义方式。
所以 C*
指向一个内存区域,其中包含一些 B
内容,然后是一些 C
内容。
你的 void*
什么都不记得了;所有这些 "intelligence" 都在 B
和 C
.