简体   繁体   English

C#中的继承和多态

[英]Inheritance and Polymorphism in C#

There's a simple question, What will the program print to the console? 有一个简单的问题, 程序将在控制台上打印什么?

I never thought that I could be wrong as much as I was with this piece of code. 我从来没有想过我会像这段代码一样犯错。 It behaved the other way around of what my logic expected from it. 它的行为与我的逻辑期望相反。

If someone could please enlighten the reason for each line printed I would be really appreciate that. 如果有人能启发每行打印的原因,我将非常感激。

And also, what is the meaning of instantiating a new Circle and casting it to a Shape? 而且,实例化一个新的Circle并将其转换为Shape的含义是什么? why is it treated also as an Ellipse? 为什么也将其视为椭圆形?

Thank you so much 非常感谢

EDIT: I was asked to specify what was I expecting the output to be. 编辑:我被要求指定我期望输出是什么。 So: 所以:

  1. creating a Circle and casting it to a Shape, I was thinking that only the Shape C'tor will be executed, as it's a Shape. 创建一个Circle并将其投射到Shape上,我当时认为只有Shape C'tor会被执行,因为它是Shape。

  2. What's the point of calling super() if it's done automatically? 如果自动完成,调用super()有什么意义? the Ellipse C'tor executed the code in the Shape C'tor. 椭圆C'tor执行Shape C'tor中的代码。

  3. Why does x1.Draw() which is casted to Shape is executing the code of Ellipse's Draw()? 为什么强制转换为Shape的x1.Draw()执行Ellipse的Draw()代码? as you can see both x1,x2 printed the same message. 如您所见,x1,x2都打印了相同的消息。

Hope I was more clear, thank you. 希望我更加清楚,谢谢。

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");
        }
    }
}

Output: 输出:

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

creating a Circle and casting it to a Shape, I was thinking that only the Shape C'tor will be executed, as it's a Shape. 创建一个Circle并将其投射到Shape上,我当时认为只有Shape C'tor会被执行,因为它是Shape。

When you write new Circle() , it creates an instance of Circle , so it calls the constructor of Circle . 当您编写new Circle() ,它将创建Circle的实例,因此将调用Circle的构造函数。 The cast is done afterwards. 投射是在此之后完成的。 Actually, in this case the cast is redundant, because a Circle already is a Shape . 实际上,在这种情况下,投射是多余的,因为Circle已经 Shape You're just assigning the instance of Circle to a variable of type Shape ; 您只是将Circle实例分配给Shape类型的变量; this way the compiler doesn't know the actual concrete type of the variable. 这样,编译器就不知道变量的实际具体类型。 The Circle instance is not actually converted to anything else. Circle实例实际上并未转换为其他任何实例。

What's the point of calling super() if it's done automatically? 如果自动完成,调用super()有什么意义? the Ellipse C'tor executed the code in the Shape C'tor. 椭圆C'tor执行Shape C'tor中的代码。

I assume you mean base() rather than super() ; 我假设你的意思是base()而不是super() but anyway, you're not calling it, the compiler does it for you automatically. 但是无论如何,您不是在调用它,而是由编译器自动为您完成。 The constructor of a derived class must always call a constructor of the base class to initialize the state of the base class. 派生类的构造函数必须始终调用基类的构造函数来初始化基类的状态。 In the case of the default constructor, you don't need to do it explicitly because the compiler does it for you. 在默认构造函数的情况下,您不需要显式地执行此操作,因为编译器会为您执行此操作。

Why does x1.Draw() which is casted to Shape is executing the code of Ellipse's Draw()? 为什么强制转换为Shape的x1.Draw()执行Ellipse的Draw()代码? as you can see both x1,x2 printed the same message. 如您所见,x1,x2都打印了相同的消息。

That's the whole point of polymorphism. 这就是多态的全部要点。 At runtime, the method that is executed depends on the actual concrete type of the object. 在运行时,执行的方法取决于对象的实际具体类型。 Since Ellipse overrides the Shape.Draw method, it is the Ellipse implementation that is executed for an instance of Ellipse . 由于Ellipse覆盖Shape.Draw方法,它是Ellipse是对于的一个实例中执行实现Ellipse

Note that in the Circle class, you didn't use the override keyword on the Draw method; 注意,在Circle类中,您没有在Draw方法上使用override关键字。 this means that Circle.Draw does not override Shape.Draw , it's just an unrelated method that just happens to have the same name. 这意味着Circle.Draw 不会覆盖Shape.Draw ,它只是恰好有相同的名称无关的方法。 It will not participate in polymorphism, it will only be called if you call it through a variable of type Circle . 它不会参与多态,只有通过Circle类型的变量调用它时,它才会被调用。

  1. For every type in the inheritance tree (at least) one constructor must be called. 对于继承树中的每种类型(至少),必须调用一个构造函数。 Hence you see every constructor print in your case. 因此,您会看到每种情况下构造函数的输出。
  2. To redirect to a specific (overload of an) constructor. 重定向到特定的(其重载)构造函数。
  3. Since the last implementation on the class is called. 自该类的最后一个实现被调用以来。 Even if the object is casted, it will still call the last type's method (unless you break inheritance through new ). 即使对象被强制转换,它仍将调用最后一个类型的方法(除非您通过new中断继承)。
  1. creating a Circle and casting it to a Shape, I was thinking that only the Shape C'tor will be executed, as it's a Shape. 创建一个Circle并将其投射到Shape上,我当时认为只有Shape C'tor会被执行,因为它是Shape。

    As you are saying: You are creating a Circle and casting it to a Shape . 正如您所说的:您正在创建一个Circle并将其转换为Shape The constructor will only be called when you are creating an instance of an object. 仅在创建对象实例时才调用构造函数。 Therefor you are simply calling the constructor of Circle . 因此,您只需调用Circle的构造函数即可。 The process of casting is not calling any constructors. 转换过程不调用任何构造函数。

  2. You always need to call the base constructor with : base() . 您始终需要使用以下命令调用基本构造函数: base() When there is a parameter less base constructor the compiler will add the : base() for you (Because its clear). 如果没有基本构造函数的参数,编译器将为您添加: base() (因为其清除)。 You can use base() to call a specific base constructor which might not be the parameterless one. 您可以使用base()来调用特定的基本构造函数,该构造函数可能不是无参数的。

  3. The Draw() method you have there in your Circle class is only known by the compiler when you have a Circle instance. 仅当您具有Circle实例时,编译器才知道您在Circle类中具有的Draw()方法。 In you case you have got a Ellipse and a Shape which don't know about the custom Draw method and are therefor calling the overridden Draw method from Ellipse 在您的情况下,您有一个不知道自定义Draw方法的EllipseShape ,因此可以从Ellipse调用重写的Draw方法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM