【问题标题】:Why do we need to have Object class as baseclass for all the classes?为什么我们需要将 Object 类作为所有类的基类?
【发布时间】:2011-03-07 17:25:37
【问题描述】:

在 C# 或 Java 或任何其他遵循 oops 概念的语言中,默认情况下通常将“对象”作为其超类。为什么我们需要将 Object 作为我们创建的所有类的基类?

当 C# 或 Java 等语言无法实现多重继承时,我们如何从另一个类派生我们的类,而它已经派生自 Object 类。这个问题可能看起来很傻,但想知道一些专家对此的看法。

【问题讨论】:

  • 所以我们不需要空指针!!!
  • 如果我们可以处理一棵树,为什么还要处理森林?

标签: c# java oop


【解决方案1】:

它就像所有从它派生的对象的模板,因此默认提供每个对象所需的一些通用功能。例如克隆、哈希码和对象锁定等。

【讨论】:

    【解决方案2】:

    多重继承是完全不同的球类游戏。

    多重继承的例子:-

    class Root
    {
    public abstract void Test();
    }
    
    class leftChild : Root
    {
    public override void Test()
    {
    }
    }
    
    class rightChild : Root
    {
    public override void Test()
    {
    }
    }
    
    class leafChild : rightChild, leftChild
    {
    }
    

    这里的问题是leafChild继承了rightChild和leftChild的Test。所以一个冲突方法的情况。这被称为钻石问题。

    但是当你使用对象作为超类时,层次结构是这样的:-

    class Object
        {
            public abstract void hashcode();
            //other methods
         }
    
        class leftChild : Object
        {
        public override void hashcode()
        {
        }
        }
    
        class rightChild : Object
        {
        public override void hashcode()
        {
        }
        }
    

    所以这里我们从 Object 派生两个类,但这就是它的结束。

    【讨论】:

      【解决方案3】:

      拥有一个单根类型的层次结构可以在很多方面都很方便。特别是,在泛型出现之前,它是像ArrayList 这样的东西起作用的唯一方法。使用泛型,它的优势要小得多——尽管我怀疑它在某些情况下仍然有用。编辑:例如,LINQ to XML 的构造模型在通过object 指定方面非常“松散”……但它工作得非常好。

      至于从不同的类派生——你直接从一个类派生,但反过来又会间接从另一个类派生,依此类推直到Object。

      请注意,“所有对象都具有共同点”,例如哈希码、相等性和监视器,我会质疑其是否明智的另一个设计决策。如果没有单一的根层次结构,这些设计决策可能不会以同样的方式做出;)

      【讨论】:

      • 对于 c# 至少有拳击——因为一切都来自对象,所以一切都可以存储在一个对象中。比 void* 好一点
      • @simendsjo:这主要在我的第一段中介绍,不是吗?这就是为什么ArrayList 是可行的。问题是,对于泛型,你还需要 Object 吗?
      • 我怀疑对于异构集合。
      • 我最近才开始接触 .Net 游戏,所以我从未真正使用过 ArrayList :)
      • @Matthias:嗯……可能……我怀疑有各种各样的小角落案例。不能说我经常使用异构集合,但我敢肯定它们有时很方便 :)
      【解决方案4】:

      只是为了比较,让我们看一下不强制执行单个根类的语言 - Objective-C。在大多数 Objective-C 环境中,将提供三个可用的根类(ObjectNSObjectNSProxy),您可以通过不声明超类来编写自己的根类。事实上,Object 已被弃用,并且仅出于遗留原因而存在,但将其包含在此讨论中会提供有用的信息。该语言是鸭子类型的,因此您可以将变量的类型声明为“任何旧对象”(写为id),那么它具有什么根类都无关紧要。

      好的,所以我们已经有了所有这些基类。事实上,即使编译器和运行时库能够到达任何需要一些通用行为的地方:根类都必须有一个名为 isa 的指针 ivar,它引用类定义结构。没有那个指针,编译器不知道如何创建一个对象结构,运行时库也不知道如何找出一个对象是什么类,它的实例变量是什么,它响应什么消息等等。

      因此,即使 Objective-C 声称有多个根类,实际上 所有 对象都必须实现一些行为。所以除了名字之外,确实有一个通用的原始超类,尽管它的 API 比 java.lang.Object 少。

      注意碰巧NSObjectNSProxy 都通过协议(如Java 接口)提供了类似于java.lang.Object 的丰富API。大多数声称处理 id 类型的 API(请记住,这是“任何旧对象”类型)实际上会假定它响应协议中的消息。当您真正需要使用一个对象时,而不是仅仅使用编译器创建它,将所有这些常见的行为(如相等、散列、字符串描述等)折叠起来是很有用的根类。

      【讨论】:

        【解决方案5】:

        好吧,Object 的多重继承并不适用——你可以把它想象成:

        “如果一个类型没有基类型,则隐式注入Object”。

        因此,应用 ad-nauseam 规则,所有类型仅从对象继承一次 - 因为在层次结构的底部必须是没有基的类型;因此它将隐式继承自Object

        至于为什么这些语言/框架有这个特性,我有几个原因:

        1) 线索的名称为“面向对象”。一切都是对象,因此一切都应该以“对象”(或等价物)为核心,否则设计原则将从一开始就被打破。

        2) 允许框架为所有类型应该/可能需要支持的常见操作提供挂钩。如哈希码生成、调试字符串输出等。

        3) 这意味着你可以避免使用会破坏东西的讨厌的类型转换——比如(((int *)(void*))value)——因为你对所有东西都有一个友好的超类型

        可能还有更多的负载 - 在我写这篇文章的时间里,已经发布了 6 个新答案;所以我会把它留在那里,希望比我更好的人能更详细地解释,也许更好:)

        【讨论】:

        • 1) 面向对象在没有单独根时仍然有效。 2) 功能可以由语言提供,而不是由库的单个根对象提供。 3) 它可能会改进一些设计not 以允许“友好的超级类型”everything
        • @nicerobot: 1) 我从来没有说过多重继承违反了面向对象。我说过,一个支持纯 OO 的平台应该有一个 Object 超类型。拥有多个根超类型是完全有效的。 2)当然它们可以由语言提供——我再一次没有说过它们不能(谁在乎功能来自哪里?)。然而,在 .Net 和 Java 的情况下,它们由超类型实现——这也意味着编译器要做的工作更少。 3) 也许是这样 - 但是你可能不会有一个纯 OO 环境?
        • @andras-zoltan 我不是在攻击你,只是在阐述可能性。至于“纯 OO”,我只是说它不需要一个通用的超类型仍然是纯 OO,这并不意味着支持多重继承。例如,在我的无根语言中,class A{}class B{} 没有共同的祖先,但该语言仍然可以强制将对象作为唯一的类型。例如,我可以实现与class String{} 没有层次关系的class Number{}class Integer : Number{},我仍然是一个纯粹的OO 环境。
        • @nicerobot:我为冒犯道歉! :) 你肯定已经优雅地表达了你的观点——我完全同意你的看法。附带说明 - 我希望我可以在 C# 中进行多重继承。 :)
        【解决方案6】:

        总之

        1) Object 类定义了所有对象必须具有的基本状态和行为,例如将自己与另一个对象进行比较、转换为字符串、等待条件变量、通知其他对象的能力条件变量已经改变,并返回对象的类。

        2)你可以让B扩展C,A扩展B。A是B的子类,B是C的子类。当然A也是C的子类。

        【讨论】:

          【解决方案7】:

          您之所以拥有 Object 基类,是因为 Object 类具有方法(例如,在 .NET 中,GetHashCode(),其中包含每个对象应该具有的通用功能)。

          多重继承确实是不可能的,但是从类B派生类A是可以的,因为A可能不会直接从Object派生,但是B会,所以所有的类最终都是从Object派生的,如果您在类的继承层次结构中走得足够远。

          【讨论】:

            【解决方案8】:

            关于您问题的第一部分,它是类如何接收公共属性和方法。这也是我们如何为可以接受任何对象的函数提供强类型参数的方式。

            关于你的第二个问题,你只是从另一个类派生你的类;然后它将是该类的后代,而后者又是 Object 的后代。没有冲突。

            【讨论】:

              【解决方案9】:

              每个类都继承编译器确保的对象这一事实。
              意思是你写的:

              class A {}
              

              编译如下:

              class A : Object{}
              

              但如果你说:

              class B : A {}
              

              Object 将在 B 的层次结构中,但不是直接位于 - 所以仍然没有多重继承。

              【讨论】:

                猜你喜欢
                • 2020-12-17
                • 2014-06-30
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-12-20
                • 2014-09-19
                相关资源
                最近更新 更多