派生和基础 class 对象的指针互换性以及标准的措辞
Pointer-interconvertibility of derived and base class objects and the Standard's wording on it
我试图了解何时可以通过指向 void 的指针将派生对象安全地转换为基子对象(我认为它应该与 reinterpret_cast
相同)。但是我能找到的标准对此的措辞让我感到困惑。首先,
Two objects a and b are pointer-interconvertible if:
— one is a standard-layout class object and the other is the first non-static data member of that object, or, if the object has no non-static data members, the first base class subobject of that object
由此无法得出可靠的结论,“或”是适用于“或”之前的整个子句还是仅适用于它的第二部分。这很重要,因为在没有非静态数据成员的情况下,我无法确定“标准布局 class 对象”是否必须与基本子对象进行指针互换。
但是在深入研究标准时我发现:
If a standard-layout class object has any non-static data members, its address is the same as the address of its first non-static data member. Otherwise, its address is the same as the address of its first base class subobject (if any).
这似乎更清楚需要“标准布局”。但仍然令人困惑。考虑以下代码:
class B { public: int b; };
class C : public B { public: int c; };
int main ()
{
C c;
B* b = &c;
std::cout << &c << " address of standard-layout class object\n";
std::cout << &c.c << " address of its first non-static data member\n";
std::cout << b << " address of first base class subobject\n";
return 0;
}
在 VS2019 上结果是:
009BFBF8 address of standard-layout class object
009BFBFC address of its first non-static data member
009BFBF8 address of first base class subobject
这不是标准所说的。你能解释一下吗?
重点在standard-layoutclass的定义中。
来自 http://www.cplusplus.com/reference/type_traits/is_standard_layout/:
A standard-layout class 是一个 class(用 class、结构或联合定义):
没有虚函数也没有虚基classes.
对其所有内容具有相同的访问控制(私有、受保护、public)
non-static 数据成员。
要么在最派生的 class 中没有 non-static 数据成员,要么
至多一个基数 class 有 non-static 个数据成员,或者没有基数
class 有 non-static 个数据成员。
它的基础class(如果有的话)本身也是一个standard-layout class.
并且,没有与其第一个 non-static 相同类型的基础 class
数据成员.
在你的例子中 class C 不匹配第三条规则,所以 它不是 standard-layout class.
此外,关于你关于 'or' 的问题,它仅适用于第二部分,即在 'or' 之后,声明仍然是关于 standard-layout class 对象,但是没有 non-static 个成员。
我试图了解何时可以通过指向 void 的指针将派生对象安全地转换为基子对象(我认为它应该与 reinterpret_cast
相同)。但是我能找到的标准对此的措辞让我感到困惑。首先,
Two objects a and b are pointer-interconvertible if:
— one is a standard-layout class object and the other is the first non-static data member of that object, or, if the object has no non-static data members, the first base class subobject of that object
由此无法得出可靠的结论,“或”是适用于“或”之前的整个子句还是仅适用于它的第二部分。这很重要,因为在没有非静态数据成员的情况下,我无法确定“标准布局 class 对象”是否必须与基本子对象进行指针互换。
但是在深入研究标准时我发现:
If a standard-layout class object has any non-static data members, its address is the same as the address of its first non-static data member. Otherwise, its address is the same as the address of its first base class subobject (if any).
这似乎更清楚需要“标准布局”。但仍然令人困惑。考虑以下代码:
class B { public: int b; };
class C : public B { public: int c; };
int main ()
{
C c;
B* b = &c;
std::cout << &c << " address of standard-layout class object\n";
std::cout << &c.c << " address of its first non-static data member\n";
std::cout << b << " address of first base class subobject\n";
return 0;
}
在 VS2019 上结果是:
009BFBF8 address of standard-layout class object
009BFBFC address of its first non-static data member
009BFBF8 address of first base class subobject
这不是标准所说的。你能解释一下吗?
重点在standard-layoutclass的定义中。 来自 http://www.cplusplus.com/reference/type_traits/is_standard_layout/:
A standard-layout class 是一个 class(用 class、结构或联合定义):
没有虚函数也没有虚基classes.
对其所有内容具有相同的访问控制(私有、受保护、public) non-static 数据成员。
要么在最派生的 class 中没有 non-static 数据成员,要么 至多一个基数 class 有 non-static 个数据成员,或者没有基数 class 有 non-static 个数据成员。
它的基础class(如果有的话)本身也是一个standard-layout class.
并且,没有与其第一个 non-static 相同类型的基础 class 数据成员.
在你的例子中 class C 不匹配第三条规则,所以 它不是 standard-layout class.
此外,关于你关于 'or' 的问题,它仅适用于第二部分,即在 'or' 之后,声明仍然是关于 standard-layout class 对象,但是没有 non-static 个成员。