【问题标题】:Inheritance and Polymorphism in C#C#中的继承和多态
【发布时间】:2015-06-07 20:28:12
【问题描述】:

有一个简单的问题,程序会在控制台打印什么?

我从没想过我会在这段代码上犯错。它的行为与我的逻辑预期相反。

如果有人能说明每行打印的原因,我将不胜感激。

另外,实例化一个新的 Circle 并将其转换为 Shape 是什么意思?为什么它也被视为椭圆?

非常感谢

编辑: 我被要求指定我期望的输出是什么。 所以:

  1. 创建一个圆形并将其转换为一个形状,我认为只有形状 C'tor 将被执行,因为它是一个形状。

  2. 如果自动调用 super() 有什么意义呢? Ellipse C'tor 执行了 Shape C'tor 中的代码。

  3. 为什么转换为Shape的x1.Draw()会执行Ellipse的Draw()的代码?如您所见,x1,x2 都打印了相同的消息。

希望我更清楚,谢谢。

namespace ConsoleApplication2
{
    class Shape
    {
        public Shape()
        { 
            Console.WriteLine("SHAPE CTOR");
        }

        public virtual void Draw()
        {
            Console.WriteLine("Shape.Draw()");
        }
    }

    class Ellipse : Shape
    {
        public Ellipse()
        {
            Console.WriteLine("ELLIPSE CTOR");
        }

        public sealed override void Draw()
        {
            Console.WriteLine("ELLIPSE.Draw()");
        }
    }

    class Circle : Ellipse
    {
        public static void Main()
        {
            Shape x1 = (Shape)new Circle();
            Ellipse x2 = (Ellipse)new Circle();
            Circle x3 = new Circle();
            x1.Draw();
            x2.Draw();
            x3.Draw();
        }

        public void Draw()
        {
            Console.WriteLine("CIRCLE DRAW");
        }
    }
}

输出:

SHAPE CTOR
ELLIPSE CTOR
SHAPE CTOR
ELLIPSE CTOR
SHAPE CTOR
ELLIPSE CTOR
ELLIPSE.Draw()
ELLIPSE.Draw()
CIRCLE DRAW

【问题讨论】:

  • 你能说得更具体点吗?您到底期望什么,为什么?
  • 这是正常行为,除非您告诉我们您的预期,正如@O.R.Mapper 所说,我们不会知道您无法理解什么。否则,这将变成关于多态性和继承的重要课程......并且网上有很多资源。
  • 我猜@johni 缺少 Circle 没有 ctor,这就是它在那里打印 shap 的原因。
  • 为了您的方便,我已经编辑了我的帖子,很抱歉造成误解。
  • @peer: Circle 有一个 ctor(它在 Main() 的前三行中的每一行中都被调用),即使它不知何故没有,这不可能与多态行为。

标签: c# inheritance polymorphism


【解决方案1】:

创建一个圆形并将其转换为一个形状,我在想只有形状 C'tor 会被执行,因为它是一个形状。

当你写new Circle()时,它会创建一个Circle的实例,所以它会调用Circle的构造函数。演员是在之后完成的。实际上,在这种情况下,演员表是多余的,因为 Circle 已经 Shape。您只是将Circle 的实例分配给Shape 类型的变量;这样编译器不知道变量的实际具体类型。 Circle 实例实际上并未转换为其他任何东西。

如果它是自动完成的,那么调用 super() 有什么意义? Ellipse C'tor 执行了 Shape C'tor 中的代码。

我假设您的意思是base() 而不是super();但无论如何,你没有调用它,编译器会自动为你做。派生类的构造函数必须始终调用基类的构造函数来初始化基类的状态。在默认构造函数的情况下,您不需要显式执行它,因为编译器会为您完成。

为什么转换为Shape的x1.Draw()会执行Ellipse的Draw()的代码?如您所见,x1,x2 都打印了相同的消息。

这就是多态性的全部意义所在。在运行时,执行的方法取决于对象的实际具体类型。由于Ellipse 覆盖了Shape.Draw 方法,因此为Ellipse 的实例执行的是Ellipse 实现。

请注意,在Circle 类中,您没有在Draw 方法上使用override 关键字;这意味着Circle.Draw 确实 覆盖Shape.Draw,它只是一个不相关的方法,只是碰巧具有相同的名称。它不会参与多态,只有通过Circle类型的变量调用才会被调用。

【讨论】:

    【解决方案2】:
    1. 对于继承树中的每种类型(至少)都必须调用一个构造函数。因此,您会看到每个构造函数都打印在您的案例中。
    2. 重定向到特定的(重载的)构造函数。
    3. 自从调用了该类的最后一个实现。即使对象被强制转换,它仍然会调用最后一个类型的方法(除非您通过new 中断继承)。

    【讨论】:

      【解决方案3】:
      1. 创建一个圆形并将其转换为一个形状,我认为只有 Shape C'tor 将被执行,因为它是一个 Shape。

        正如您所说:您正在创建 Circle 并将其转换为 Shape。只有在创建对象的实例时才会调用构造函数。因此,您只需调用Circle 的构造函数。强制转换的过程不调用任何构造函数。

      2. 您始终需要使用: base() 调用基本构造函数。当有一个无参数的基本构造函数时,编译器将为您添加: base()(因为它很清楚)。您可以使用base() 调用可能不是无参数的特定基本构造函数。

      3. 只有当你有一个 Circle 实例时,你的 Circle 类中的 Draw() 方法才会被编译器知道。在您的情况下,您有一个 Ellipse 和一个 Shape 不知道自定义 Draw 方法,因此从 Ellipse 调用覆盖的 Draw 方法

      【讨论】:

      • “对象将被实例化,然后将被转换为形状”——我担心这是误导。该对象根本不会被转换或更改。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-26
      • 1970-01-01
      • 2013-10-24
      • 1970-01-01
      • 1970-01-01
      • 2015-01-02
      • 1970-01-01
      相关资源
      最近更新 更多