当S是T的子类的小事,是可以安全使用的S数组,其中T的阵列预计? [英] When S is a trivial subclass of T, is it safe to use an array of S where an array of T is expected?
问题描述
考虑一对相关结构的以下声明。在子类中增加了没有成员变量,唯一的成员函数是一个构造函数,什么也不做,但它的所有参数转发给基类的构造函数。
结构基地{
基地(int类型的,字符常量* B):
一(a)中,B(B)
{}
int类型的;
字符常量* B;
};结构后代:基本{
后裔(int类型的,字符常量* B):
碱(A,B)
{}
};
现在考虑使用这些类型如下code。功能富
预计将收到基本
的数组。然而,主
定义后代
的数组并传递到富
代替。
无效美孚(基地*数组,无符号LEN)
{
/ *下;阵列的制造&gt访问内容; * /
}诠释的main()
{
后裔main_array [] = {
后裔(0,零),
后裔(1,1)
};
美孚(main_array,2);
返回0;
}
定义此计划的行为?其答案是否依赖于富
的身体,就像它是否写入阵列或它只读取?
如果的sizeof(衍生)
不等于的sizeof(基本)
,那么行为是根据答案不确定约一个基地指针previous问题派生对象的数组的。是否有任何机会中的对象的这个的问题将有不同的大小有关系吗?
定义此计划的行为?其答案是否依赖于foo的主体中,例如是否其写入到阵列或从它仅读?
块引用>我要危险的回答说,该计划被很好地定义(只要
富
是),即使它是写在另一种语言(如C)。
如果
的sizeof(衍生)
不等于的sizeof(基本)
,那么行为是根据答案不确定约基类指针派生的对象数组的previous问题。是否有机会在这个问题上的物体都会有不同的大小有关系吗?
块引用>我不这么认为。根据我的标准(*)第9.2节第17条
阅读
两个标准布局结构(第9条)类型是布局兼容的,如果他们有相同数量的非静态
数据成员和相应的非静态数据成员(按照声明顺序)具有布局兼容
类型(3.9)。
块引用>§9条款7至9详细的布局保持兼容的要求:
7 A 标准布局的类是一类:
有型非标准布局类的没有非静态数据成员(或这些类型的数组)或引用,
没有虚函数(10.3),没有虚基类(10.1),
对所有非静态数据成员相同的访问控制(第11条),
没有非标准布局基类,
或者具有在最派生类,并在与非静态数据成员最多有一个基类没有非静态数据成员,或具有与非静态数据成员没有基类,以及
具有相同类型的无基类作为第一非静态数据成员。
8 A 标准布局结构的是定义一个标准的布局类的类键的
结构
或在类键的类
。 A 标准布局工会的与的类键定义的标准布局类的联盟
。
9的注意:的标准布局类是与用其他编程语言code进行通信的。它们的布局在9.2规定。 - 注完的]
块引用>请注意尤其是最后一个子句(与§3.9相结合) - 根据我阅读这是保证,只要你不增加太多的C ++的东西(虚拟函数等,从而违反了标准布局的要求)的结构/类将表现为C的结构添加了语法糖。
有人会怀疑有合法性,如果
基本
没有一个构造函数?我不认为这样的模式(从C派生结构添加一个构造函数/辅助功能)是地道的。我愿意说我错了,欢迎补充/更正的可能性。
(*)实际上,我看这里N3290,但实际标准应尽量接近。
Consider the following declarations of a pair of related structs. The descendant class adds no member variables, and the only member function is a constructor that does nothing but forward all its arguments to the base class's constructor.
struct Base { Base(int a, char const* b): a(a), b(b) { } int a; char const* b; }; struct Descendant: Base { Descendant(int a, char const* b): Base(a, b) { } };
Now consider the following code using those types. Function
foo
expects to receive an array ofBase
. However,main
defines an array ofDescendant
and passes that tofoo
instead.void foo(Base* array, unsigned len) { /* <access contents of array> */ } int main() { Descendant main_array[] = { Descendant(0, "zero"), Descendant(1, "one") }; foo(main_array, 2); return 0; }
Is behavior of this program defined? Does the answer depend on the body of
foo
, like whether it writes to the array or only reads from it?If
sizeof(Derived)
is unequal tosizeof(Base)
, then behavior is undefined according to the answers to a previous question about a base pointer to an array of derived objects. Is there any chance the objects in this question will have differing sizes, though?解决方案Is behavior of this program defined? Does the answer depend on the body of foo, like whether it writes to the array or only reads from it?
I'm gonna hazard an answer saying that the program is well defined (as long as
foo
is) even if it is written in another language (e.g. C).If
sizeof(Derived)
is unequal tosizeof(Base)
, then behavior is undefined according to the answers to a previous question about a base pointer to an array of derived objects. Is there any chance the objects in this question will have differing sizes, though?I don't think so. According to my reading of the standard(*) §9.2 clause 17
Two standard-layout struct (Clause 9) types are layout-compatible if they have the same number of non-static data members and corresponding non-static data members (in declaration order) have layout-compatible types (3.9).
§9 clauses 7 through 9 detail the requirements for layout-compability:
7 A standard-layout class is a class that:
has no non-static data members of type non-standard-layout class (or array of such types) or reference,
has no virtual functions (10.3) and no virtual base classes (10.1),
has the same access control (Clause 11) for all non-static data members,
has no non-standard-layout base classes,
either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and
has no base classes of the same type as the first non-static data member.
8 A standard-layout struct is a standard-layout class defined with the class-key
struct
or the class-keyclass
. A standard-layout union is a standard-layout class defined with the class-keyunion
.9 [ Note: Standard-layout classes are useful for communicating with code written in other programming languages. Their layout is specified in 9.2. — end note ]
Note especially the last clause (combined with §3.9) - according to my reading this is guaranteeing that as long as you're not adding too much "C++ stuff" (virtual functions etc. and thus violating the standard-layout requirement) your structs/classes will behave as C structs with added syntactical sugar.
Would anyone have doubted the legality if
Base
didn't have a constructor? I don't think so as that pattern (deriving from a C structure adding a constructor/helper functions) is idiomatic.I'm open to the possibility that I'm wrong and welcome additions/corrections.
(*) I'm actually looking at N3290 here, but the actual standard should be close enough.
这篇关于当S是T的子类的小事,是可以安全使用的S数组,其中T的阵列预计?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!