Clo*_*737 18 delphi inheritance records class
我长期以来想知道的东西:为什么Delphi记录不能继承(因此所有其他重要的OOP功能)?
这基本上会使记录成为堆栈分配的类版本,就像C++类一样,并且会使"对象"(注意:非实例)过时.我没有看到任何问题.这也是实施记录前瞻性声明的好机会(我仍然感到困惑,为什么它仍然缺失).
你觉得这有什么问题吗?
Bar*_*lly 25
与此问题相关,有两种继承:接口继承和实现继承.
接口继承通常意味着多态性.这意味着如果B是从A派生的,那么类型B的值可以存储在类型A的位置.由于切片,这对于值类型(如记录)而不是引用类型是有问题的.如果B大于A,则将其存储在类型A的位置将截断该值 - B在其定义中添加的超出A的那些字段将丢失.
从这个角度来看,实现继承的问题较少.如果Delphi有记录继承,但只有实现,而不是接口,事情就不会太糟糕.唯一的问题是,只需将类型A的值设为B类型的字段,就可以完成实现继承所需的大部分操作.
另一个问题是虚拟方法.虚方法分派需要某种每值标记来指示值的运行时类型,以便可以发现正确的重写方法.但是记录没有任何地方存储这种类型:记录的字段是它拥有的所有字段.对象(旧的Turbo Pascal类型)可以具有虚拟方法,因为它们具有VMT:层次结构中用于定义虚拟方法的第一个对象隐式地将VMT添加到对象定义的末尾,从而增长它.但Turbo Pascal对象具有上述相同的切片问题,这使它们成为问题.值类型的虚方法有效地需要接口继承,这意味着切片问题.
因此,为了正确支持记录接口继承,我们需要某种解决切片问题的方法.拳击将是一种解决方案,但它通常要求垃圾收集可用,并且它会在语言中引入歧义,在这里可能不清楚你是在使用值还是引用 - 有点像Integer vs Java中的int与autoboxing.至少在Java中,对于盒装vs未装箱的"种类"值类型,有单独的名称.另一种进行拳击的方法就像Google Go及其接口,这是一种没有实现继承的接口继承,但需要单独定义接口,并且所有接口位置都是引用.当接口引用引用时,值类型(例如记录)被加框.而且当然,
记录和类/对象是Delphi中两个截然不同的东西.基本上Delphi记录是一个C结构 - Delphi甚至支持语法来做一些事情,比如有一个可以作为4个16位整数或2个32位整数访问的记录.比如struct,record在面向对象编程之前可以追溯到语言(Pascal时代).
像结构一样,记录也是内联的内存块,而不是指向一块内存的指针.这意味着当您将记录传递给函数时,您传递的是副本,而不是指针/引用.这也意味着当你在代码中声明一个记录类型变量时,它在编译时确定它有多大 - 函数中使用的记录类型变量将在堆栈上分配(而不是作为堆栈上的指针,但是4,10,16等字节结构).这种固定大小不适合多态性.
我看到的唯一问题(我可能是短视或错误)是目的.记录用于存储数据,而对象用于操纵和使用所述数据.为什么存储柜需要操作例程?
你是对的,在记录中添加继承本质上会将它们变成C++类.这就是你的答案:它没有完成,因为那将是一件可怕的事情.你可以有堆栈分配的值类型,或者你可以有类和对象,但混合这两个是一个非常糟糕的主意.一旦你这样做,你最终会遇到各种各样的生命周期管理问题,并最终不得不在语言中构建像C++的RAII模式这样丑陋的黑客来处理它们.
结论:如果您想要一种可以继承和扩展的数据类型,请使用类.这就是他们的目的.
编辑:为了回应Cloud的问题,这不是一个可以通过一个简单的例子来证明的东西.整个C++对象模型都是一场灾难.它可能看起来不像一个近距离; 你必须了解几个相互关联的问题才能真正掌握全局.RAII只是金字塔顶端的混乱.如果我有时间,也许本周晚些时候我会在我的博客上写一个更详细的解释.