当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?

查看:136
本文介绍了当S是T的子类的小事,是可以安全使用的S数组,其中T的阵列预计?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑一对相关结构的以下声明。在子类中增加了没有成员变量,唯一的成员函数是一个构造函数,什么也不做,但它的所有参数转发给基类的构造函数。

 结构基地{
  基地(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 of Base. However, main defines an array of Descendant and passes that to foo 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 to sizeof(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 to sizeof(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-key class. A standard-layout union is a standard-layout class defined with the class-key union.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆