将派生对象存储到其基类型的集合中——为啥它会起作用?

Posted

技术标签:

【中文标题】将派生对象存储到其基类型的集合中——为啥它会起作用?【英文标题】:Storing derived objects to a collection of its base type--why does it work?将派生对象存储到其基类型的集合中——为什么它会起作用? 【发布时间】:2018-04-02 21:59:10 【问题描述】:

我创建了一个被视为地图的 20x20 多维数组。

private LinkedList<Item>[,] m_map = new LinkedList<Item>[width, height];

每个单元格都是一个Item类型的链表。武器、盔甲等物品可以放入每个单元格中。

我有以下类层次结构:

class Item
 
    public string name; 


class Weapon : Item

    public int damage;


class Armor : Item

    public int ar;
    public int weight;

我有点惊讶,并希望接受这方面的教育。由于类型是 LinkedList,我不认为我可以存储一个 Armor 类型并检索它。这就是我检索特定项目类型的方式:

    /// <summary>
    /// Gets a list of weapons at the given coordinates.
    /// </summary>
    /// <param name="x">The map's horizontal position.</param>
    /// <param name="y">The map's vertical position.</param>
    /// <returns>Returns a list of weapons at the given coordinates.</returns>
    public List<Weapon> GetWeapons(int x, int y)
    
        List<Weapon> weapons = new List<Weapon>();

        foreach (Item item in m_map[x, y])
        
            if (item is Weapon)
            
                weapons.Add(item as Weapon);
            
        

        return weapons;
    

Item 包含的字段比 Armor 少,所以我认为 LinkedList 类型会比 Armor 小。然而,它似乎有足够的空间来保存一个 Armor 对象。我能够检索 Armor 的数据。

当您将派生类型及其基类型存储到链接列表时,编译器是否为其派生类型腾出足够的内存?我很惊讶我可以检索 Armor 类型并仍然获得其派生数据(ar,重量)。

有人能解释一下为什么会这样吗?谢谢。

【问题讨论】:

它存储references,如果你熟悉像C这样的语言,它们本质上是指针。这是使多态起作用的唯一方法。所有对象引用的大小相同。 哦,我明白了。所以集合存储引用而不是二进制副本。 参考类型。对于值类型,它存储一个副本。另见:***.com/questions/14669651/… 【参考方案1】:

正如 Cody Gray 在他的评论中所写,LinkedList 存储的是引用,而不是值。

对引用的简单解释是,它是内存中实际值所在位置的地址。 由于您只存储引用,因此包含 100 件物品的列表所消耗的内存量与包含 100 件武器或盔甲的列表所消耗的内存量相同。

但是,这只是您可以将派生类实例存储在父类列表中的部分原因 - 另一部分是称为多态性的基本 OOP 概念 - ArmorWeapon 实际上是Item 的一种类型,使您可以将它们中的每一个存储在任何类型为Item 的强类型集合中,因为您可以使用Item 类型的引用来指向一个实例ArmorWeapon

回答您对 Cody 的评论 - 不。集合存储您决定存储的任何内容。例如,如果您要声明int 的列表,它将存储实际值,因为int 是一个值类型。

您可能想了解value types 与reference types。

主要区别在于值类型变量直接包含值, 而引用类型变量包含一个指向实际值存储位置的“指针”。

【讨论】:

我了解引用和值类型。我不明白的是,如果一个 Item 类型包含 2 个字段(比如两个整数),那就是 64 个字节的空间。如果它指向可能有 4 个整数(128 字节)的 Armor 类型,则 Item 指向一个比它自己大的对象,但它仍然能够检索其数据。我想了解它是如何做到的。 * 对不起,清晨:8字节,16字节。 你问这个问题意味着你不明白什么是引用。引用的大小始终相同,因为它不是实际数据,几乎是指向存储数据的地址的指针。这意味着对包含 100 个 Int64 值成员的类实例的引用与对包含单个 Int16 成员的类实例的引用大小完全相同。

以上是关于将派生对象存储到其基类型的集合中——为啥它会起作用?的主要内容,如果未能解决你的问题,请参考以下文章

此异步等待不应该工作。为啥它会起作用?

CNN对象检测和水印图像训练,它会起作用吗?

OOP3(继承中的类作用域/构造函数与拷贝控制/继承与容器)

内部抽象方法。为啥会有人拥有它们?

继承中类的作用域

是否可以使用其基类构造函数创建派生类的指针而不修改派生类的布局?