• 深入OOP(第三天):多态性和继承(动态绑定/运行时多态性)


    1. 介绍 在我们之前的部分学习OOP系列中,我们谈论更多的是编译时多态参数关键字、继承、基础关键字等。这部分的系列文章将更加专注于运行时多态也叫后期绑定。我们将使用相同的技术的学习,理论与实践更少。我们将小代码片段来学习这个概念更加深入。掌握这个概念就像学习OOP的50%以上。 2. 的必备条件 因为这是本系列的第三部分,我希望我的读者是专家在编译时多态和继承。虽然不管你直接开始学习这篇文章,以后你可以把其他文章。 3.路线图 我们的路线图作为学习面向对象是明确的定义,但是我们只是修改: ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 深入OOP(第一天):多态和继承(早期绑定/编译时多态)深入OOP(第二天):多态和继承(继承)潜水OOP(第三天):多态和继承(动态绑定/运行时多态)潜水在OOP(第四天):多态和继承(关于Abstarct类在c#中)潜水在OOP(第五天):都是用c#访问修饰符(公共/私人/保护/内部/密封/常量/只读的字段)潜水OOP(6天):理解枚举在c#中(一个实际的方法)深入OOP(第七天):用c#属性(一个实际的方法)深入OOP(8天):用c#索引器(一个实际的方法)潜水印锑OOP(9天):了解c#事件(Insight)学习c#(第十天):代表在c#中(一个实际的方法)学习c#(11天):c#事件(一个实际的方法) 4. 运行时多态或后期绑定和动态绑定 在简单的c#语言,在运行时多态或方法覆盖,我们可以覆盖基类的方法通过创建类似的方法在派生类可以通过使用继承原则和使用“虚拟,覆盖”关键字。 5. 新用c#和覆盖关键词是什么? ,,,,,,,,,,,,,,,,,,,,,,,,,,,, 创建一个名为InheritanceAndPolymorphism在Visual Studio的控制台应用程序。 把两个类并保持Program.cs。这两个类将被命名为ClassA.cs ClassB.cs和每堂课上添加一个方法如下: ClassA 隐藏,复制Code

    public class ClassA
        {
            public void AAA()
            {
                Console.WriteLine("ClassA AAA");
            }
    
            public void BBB()
            {
                Console.WriteLine("ClassA BBB");
            }
    
            public void CCC()
            {
                Console.WriteLine("ClassA CCC");
            }
        }

    ClassB 隐藏,复制Code

    public class ClassB
    {
        public void AAA()
        {
            Console.WriteLine("ClassB AAA");
        }
    
        public void BBB()
        {
            Console.WriteLine("ClassB BBB");
        }
    
        public void CCC()
        {
            Console.WriteLine("ClassB CCC");
        }
    }
    

    Program.cs 隐藏,复制Code

    /// <summary>
    /// Program: used to execute the method.
    /// Contains Main method.
    /// </summary>
    public class Program
    {
        private static void Main(string[] args)
        {
    
        }
    }
    

    我们看到的都是ClassA和ClassB类具有相同数量的方法具有类似名称的类。现在让我们从ClassB继承ClassA和创建类的实例并调用program.cs的方法。 所以我们两个类的代码就变成: 隐藏,收缩,复制Code

    /// <summary>
    /// ClassB, acting as a base class
    /// </summary>
    public class ClassB
    {
        public void AAA()
        {
            Console.WriteLine("ClassB AAA");
        }
    
        public void BBB()
        {
            Console.WriteLine("ClassB BBB");
        }
    
        public void CCC()
        {
            Console.WriteLine("ClassB CCC");
        }
    }
    
    /// <summary>
    /// Class A, acting as a derived class
    /// </summary>
    public class ClassA : ClassB
    {
        public void AAA()
        {
            Console.WriteLine("ClassA AAA");
        }
    
        public void BBB()
        {
            Console.WriteLine("ClassA BBB");
        }
    
        public void CCC()
        {
            Console.WriteLine("ClassA CCC");
        }
    }
    

    Program.cs 隐藏,复制Code

    /// <summary>
    /// Program: used to execute the method.
    /// Contains Main method.
    /// </summary>
    public class Program
    {
        private static void Main(string[] args)
        {
            ClassA x = new ClassA();
            ClassB y=new ClassB();
            ClassB z=new ClassA();
    
            x.AAA(); x.BBB(); x.CCC();
            y.AAA(); y.BBB();y.CCC();
            z.AAA(); z.BBB(); z.CCC();
        }
    }
    

    现在按F5,即。运行代码,我们得到了什么? 输出 隐藏,复制Code

    ClassA AAA
    ClassA BBB
    ClassA CCC
    ClassB AAA
    ClassB BBB
    ClassB CCC
    ClassB AAA
    ClassB BBB
    ClassB CCC 

    但随着输出,我们也有三个警告。 警告 隐藏,复制Code

    'InheritanceAndPolymorphism.ClassA.AAA()' hides inherited member 
    'InheritanceAndPolymorphism.ClassB.AAA()'. Use the new keyword if hiding was intended.
    
    'InheritanceAndPolymorphism.ClassA.BBB()' hides inherited member 
    'InheritanceAndPolymorphism.ClassB.BBB()'. Use the new keyword if hiding was intended.
    
    'InheritanceAndPolymorphism.ClassA.CCC()' hides inherited member 
    'InheritanceAndPolymorphism.ClassB.CCC()'. Use the new keyword if hiding was intended.

    记住:在c#中,我们可以将一个对象的基类派生类而不是反之亦然。 ClassA类的超类是ClassB类。这意味着ClassA是派生类和ClassB是基类。类ClassA包括ClassB和更多的东西。所以我们可以得出这样的结论:ClassA大于ClassB的对象的对象。因为从ClassB ClassA是遗传的,它包含自己的方法和属性。此外,它还将包含方法/属性,也是从ClassB继承。 取对象的情况下y。它看起来像ClassB创建一个对象并初始化,也看起来像ClassB,很好。现在,当我们调用AAA的方法和BBB和CCC对象y,我们知道它将从ClassB调用它们。 对象x是这样ClassA,即。派生类。是初始化一个对象,看起来像ClassA。当我们调用AAA, BBB和CCC方法通过x,它调用AAA, BBB ClassA和CCC。 现在我们正在处理是一个有点棘手的情形: 对象的z看起来像ClassB,但现在是初始化一个对象,看起来像ClassA不给一个错误如前所述。但是没有改变我们获取和在输出对象的行为是相同的,y。因此,初始化一个对象,看起来像ClassB或ClassA似乎并不重要。 6. 实验 让我们试验的代码,把覆盖在AAA和新BBB ClassA方法背后,即。派生类。 我们的代码如下: ClassB 隐藏,复制Code

    /// <summary>
    /// ClassB, acting as a base class
    /// </summary>
    public class ClassB
    {
        public void AAA()
        {
            Console.WriteLine("ClassB AAA");
        }
    
        public void BBB()
        {
            Console.WriteLine("ClassB BBB");
        }
    
        public void CCC()
        {
            Console.WriteLine("ClassB CCC");
        }
    }
    

    ClassA 隐藏,复制Code

    /// <summary>
    /// Class A, acting as a derived class
    /// </summary>
    public class ClassA : ClassB
    {
        public override void AAA()
        {
            Console.WriteLine("ClassA AAA");
        }
    
        public new void BBB()
        {
            Console.WriteLine("ClassA BBB");
        }
    
        public void CCC()
        {
            Console.WriteLine("ClassA CCC");
        }
    }
    

    程序。cs 隐藏,复制Code

    /// <summary>
    /// Program: used to execute the method.
    /// Contains Main method.
    /// </summary>
    public class Program
    {
        private static void Main(string[] args)
        {
            ClassB y = new ClassB();
            ClassA x = new ClassA();
            ClassB z = new ClassA();
    
            y.AAA(); y.BBB(); y.CCC();
            x.AAA(); x.BBB(); x.CCC();
            z.AAA(); z.BBB(); z.CCC();
    
            Console.ReadKey();
        }
    }
    

    我们得到的输出: 隐藏,复制Code

    Error:  'InheritanceAndPolymorphism.ClassA.AAA()': cannot override inherited member 
    'InheritanceAndPolymorphism.ClassB.AAA()' because it is not marked virtual, abstract, or override

    * InheritanceAndPolymorphism:这是我用于控制台应用程序的命名空间,所以你可以忽略它。 在派生类方法中添加这两个修饰符后,我们得到一个错误,该错误告诉我们在基类中标记方法是虚的、抽象的还是重写的。 好吧,这对我有什么关系? ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 我将基类的所有方法都标记为虚的。 现在我们的代码和输出如下: 隐藏,收缩,复制Code

    /// <summary>
        /// ClassB, acting as a base class
        /// </summary>
        public class ClassB
        {
            public virtual void AAA()
            {
                Console.WriteLine("ClassB AAA");
            }
    
            public virtual void BBB()
            {
                Console.WriteLine("ClassB BBB");
            }
    
            public virtual void CCC()
            {
                Console.WriteLine("ClassB CCC");
            }
        }
    
        /// <summary>
        /// Class A, acting as a derived class
        /// </summary>
        public class ClassA : ClassB
        {
            public override void AAA()
            {
                Console.WriteLine("ClassA AAA");
            }
    
            public new void BBB()
            {
                Console.WriteLine("ClassA BBB");
            }
    
            public void CCC()
            {
                Console.WriteLine("ClassA CCC");
            }
        }
    
        /// <summary>
        /// Program: used to execute the method.
        /// Contains Main method.
        /// </summary>
        public class Program
        {
            private static void Main(string[] args)
            {
                ClassB y = new ClassB();
                ClassA x = new ClassA();
                ClassB z = new ClassA();
    
                y.AAA(); y.BBB(); y.CCC();
                x.AAA(); x.BBB(); x.CCC();
                z.AAA(); z.BBB(); z.CCC();
    
                Console.ReadKey();
            }
        }

    输出 隐藏,复制Code

    ClassB AAA
    ClassB BBB
    ClassB CCC
    ClassA AAA
    ClassA BBB
    ClassA CCC
    ClassA AAA
    ClassB BBB
    ClassB CCC

    注意:需要重写修饰符,因为派生类方法将获得优先级并被调用。 我们在这里看到,只有对象z的工作方式有一个很小的变化,而x和y没有,这个奇怪的输出是在我们在基类方法中添加了virtual modifier之后才出现的。区别在于对象z. z看起来像基类ClassB,但被初始化为一个实例,看起来像派生类ClassA。c#知道这个事实。当我们运行z. aaa()时,c#记得实例z是由一个ClassA对象初始化的,因此它首先进入类ClassA,这太明显了。这里方法有一个修饰符覆盖,字面意思是,忘掉z的数据类型是ClassB,从ClassA调用AAA,因为它覆盖了基类的AAA。需要重写修饰符,因为派生类方法将获得优先级并被调用。 我们想要重写基类ClassB的AAA。我们实际上是在告诉c#这个AAA与基类中的AAA相似。 新关键字的作用与覆盖关键字完全相反。如我们所见,方法BBB具有新的修饰符。z.BBB()从ClassB调用BBB,而不是ClassA。New意味着方法BBB是一个新方法,它与基类中的BBB完全没有关系。它可能与基类中的名称BBB相同,但这只是巧合。由于z看起来像ClassB, ClassB的BBB被调用即使ClassA中有BBB。当我们不编写任何修饰符时,就假定我们编写了new。所以每次我们编写一个方法时,c#都假设它与基类无关。 注意:只有在基类中的方法是虚拟方法时,才能使用new和override等修饰符。虚意味着基类授予我们从派生类而不是基类调用方法的权限。但是,如果我们的派生类方法必须被调用,我们必须添加修饰符覆盖。 7. 运行时多态性有三个类 让我们开始更多的行动。我们再让一个班的同学参加这个话剧吧。让我们添加一个名为ClassC的类,并设计我们的三个类和program.cs如下: 隐藏,收缩,复制Code

    /// <summary>
    /// ClassB, acting as a base class
    /// </summary>
    public class ClassB
    {
        public  void AAA()
        {
            Console.WriteLine("ClassB AAA");
        }
    
        public virtual void BBB()
        {
            Console.WriteLine("ClassB BBB");
        }
    
        public virtual void CCC()
        {
            Console.WriteLine("ClassB CCC");
        }
    }
    
    /// <summary>
    /// Class A, acting as a derived class
    /// </summary>
    public class ClassA : ClassB
    {
        public virtual void AAA()
        {
            Console.WriteLine("ClassA AAA");
        }
    
        public new void BBB()
        {
            Console.WriteLine("ClassA BBB");
        }
    
        public override void CCC()
        {
            Console.WriteLine("ClassA CCC");
        }
    }
    
    /// <summary>
    /// Class C, acting as a derived class
    /// </summary>
    public class ClassC : ClassA
    {
        public override void AAA()
        {
            Console.WriteLine("ClassC AAA");
        }
    
        public void CCC()
        {
            Console.WriteLine("ClassC CCC");
        }
    }
    
    /// <summary>
    /// Program: used to execute the method.
    /// Contains Main method.
    /// </summary>
    public class Program
    {
        private static void Main(string[] args)
        {
            ClassB y = new ClassA();
            ClassB x = new ClassC();
            ClassA z = new ClassC();
    
            y.AAA(); y.BBB(); y.CCC();
            x.AAA(); x.BBB(); x.CCC();
            z.AAA(); z.BBB(); z.CCC();
    
            Console.ReadKey();
        }
    }
    

    输出 隐藏,复制Code

    ClassB AAA
    ClassB BBB
    ClassA CCC
    ClassB AAA
    ClassB BBB
    ClassA CCC
    ClassC AAA
    ClassA BBB
    ClassA CCC

    不要害怕我们已经采取的漫长的例子。这将帮助你更详细地了解这个概念。我们已经学习了,我们可以初始化一个基对象为派生对象。反之则会导致错误。这将导致基类的实例被初始化为派生类的实例。现在的问题是什么时候调用哪个方法。来自基类或派生类的方法。 注意:如果基类对象声明方法为virtual,而派生类使用修饰符重写,则派生类方法将被调用。否则,基类方法将被执行。因此,对于虚拟方法,创建的数据类型仅在运行时决定。 请记住:所有未标记为virtual的方法都是非virtual的,并且要调用的方法是在编译时决定的,这取决于对象的静态数据类型。 如果类的对象被初始化为相同的数据类型,那么上面的规则将不适用。当我们有不匹配时,我们总是需要规则来解决不匹配。因此,我们可以在基类的对象可以调用派生类中的方法的场景中结束。 对象y看起来像ClassB,但在这里被初始化为派生类。ClassA。 y.a aaa()首先查找类ClassB。在这里,它验证方法AAA是否被标记为virtual。答案显然是否定的,因此一切都会停止,并从类ClassB调用方法AAA。 y。BBB也做同样的事情,但是这个方法现在在类ClassB中定义为virtual。因此c#查看的是类ClassA,也就是它被初始化的类。在这里,BBB被标记为修饰语“new”。这意味着BBB是一个与基类中的方法无关的新方法。他们只是偶然地共用了一个名字。所以没有所谓的BBB方法派生类中的新BBB),来自基类的一个被调用。在y.c ccc()的场景中,同样的步骤被再次执行,但是在类ClassA中,我们看到修饰符覆盖了,它通过行为覆盖了基类中的方法。我们实际上是在告诉c#在类ClassA中调用这个方法,而不是在基类中调用这个方法。, ClassB。 ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 我刚从网上得到这张图片,它描述了我们的班级现状。我们现在正在学习像魅力这样的概念。OOP现在变得越来越简单了。 对象x看起来也像类ClassB,现在用一个对象初始化,这个对象看起来像我们新引入的类ClassC,而不是像以前那样的类ClassA。因为AAA是一个非虚方法,它从ClassB中调用。对于方法BBB, c#现在查看类ClassC。在这里,它没有找到名为BBB的方法,因此最终传播并现在查看类ClassA。因此,上述规则不断重复,并从类ClassB中调用。对于x。在类ClassC中,默认情况下它已经被标记为new,因此这个方法与类ClassB中声明的方法没有任何关系。来自ClassC的那个不会被调用但来自ClassB的那个被标记为重载。 现在,如果我们在ClassC中稍微修改一下我们的CCC方法,并将其更改为如下代码: 隐藏,复制Code

    public override void CCC()
    {
        Console.WriteLine("ClassC CCC");
    }
    

    我们改变了默认的新覆盖,ClassC的CCC现在将被调用。 最后一个对象z看起来像ClassA,但现在被初始化为一个类似派生类ClassC的对象,我们知道我们可以这样做。因此,在调用z.AAA()时,首先查看类ClassA,它在那里被标记为virtual。你还记得AAA在类ClassB中是非虚拟的,但在类a中被标记为虚拟的吗?从现在开始,方法AAA在ClassC中也是虚拟的,但在ClassB中不是。虚拟总是像瀑布一样从上到下流动。因为AAA()被标记为virtual,所以我们现在来看类ClassC。在这里,它被标记为override,因此从类ClassC调用AAA()。在BBB()的情况下,BBB()在类ClassB中被标记为virtual,在类a中被标记为new,但是由于在类c中没有方法BBB,因此在这种情况下修饰符都不重要。最后,它从类ClassA中调用。最后,对于方法CCC,在类ClassC中标记为new。因此,它与类ClassA中的CCC没有关系,这会导致方法CCC从类a而不是类b被调用。 一个例子: 隐藏,复制Code

    internal class A
    {
        public virtual void X()
        {
        }
    }
    
    internal class B : A
    {
        public new void X()
        {
        }
    }
    
    internal class C : B
    {
        public override void X()
        {
        }
    }
    

    在上面的例子中,代码是非常自我解释的,我们将得到的输出是: 隐藏,复制Code

    Error: 'InheritanceAndPolymorphism.C.X()': cannot override inherited member 
    'InheritanceAndPolymorphism.B.X()' because it is not marked virtual, abstract, or override

    奇怪!当类B中的方法X()被标记为new时,我们得到了一个错误。这意味着它隐藏的X()类a。如果我们讨论类C, B不供应了一个名为X的方法B类中定义的方法X无关类中定义的方法X a .这意味着B类的方法X不继承虚拟X()方法修饰符的类a。这就是编译器抱怨。因为B中的方法X没有虚拟修饰符,所以在C中我们不能使用修饰符覆盖。但是,我们可以使用修饰符new并删除警告? 8. 断绝了关系 隐藏,收缩,复制Code

    internal class A
    {
        public virtual void X()
        {
            Console.WriteLine("Class: A ; Method X");
        }
    }
    
    internal class B : A
    {
        public new virtual void X()
        {
            Console.WriteLine("Class: B ; Method X");
        }
    }
    
    internal class C : B
    {
        public override void X()
        {
            Console.WriteLine("Class: C ; Method X");
        }
    }
    
    /// <summary>
    /// Program: used to execute the method.
    /// Contains Main method.
    /// </summary>
    public class Program
    {
        private static void Main(string[] args)
        {
            A a = new C();
            a.X();
            B b = new C();
            b.X();
    
            Console.ReadKey();
        }
    }
    

    输出 隐藏,复制Code

    Class: A ; Method X
    Class: C ; Method X

    如果在上面的代码中,我们从类C中的X()中删除修饰符override,我们得到: 输出 隐藏,复制Code

    Class: A ; Method X
    Class: B ; Method X

    ,,,,,,,,,,,,,,,,, 是的,这就是虚方法的问题。有时候,他们太混乱了,结果与我们期望的完全不同。对象a看起来像a,但被初始化为派生类C。因为X是虚拟的,所以c#现在去查看类C,但在查看类C之前,它意识到在类B中,X是新的。就是这样,这个东西削减与X的A .因此关键字新与虚拟之前,否则覆盖修饰符会在课堂上给我们一个错误C . X在B类标记为新方法,与A类无关,C类继承一个新的也无关的类A . X C类与类A的X (B类,而不是因此X类调用。 在第二种情况下,对象b看起来像b类,但反过来被初始化为一个对象的类C . C #首先看类b这里X是新和虚拟,这使得它的独特方法X可悲的是,X C有覆盖修饰符将它的X C隐藏了X b这个调用的C。如果我们从类C中的X中删除override修饰符,默认值将是新的,这样就切断了与b的X的关系,因此,一种新方法,B的X被调用。 一个虚拟的方法不能被修饰词的静态,抽象或覆盖。非虚方法是不变的。这意味着调用相同的方法,不论是否存在一个基类或派生类。在一个虚拟的方法中,对象的运行时类型决定的方法调用,而不是编译时类型是在非虚拟方法。虚方法,存在一个最派生的实现总是被调用。 9. 运行时多态与四类 好的!我们做了大量代码。如果我告诉你,我们要添加一个类的代码,类ClassD是的。所以我们去更深入多态和继承的概念。 我们再添加一个类的三个类解决方案我们正在(记得吗?)。所以我们的新类命名ClassD。 让我们用我们的新类采取行动: 隐藏,收缩,复制Code

    /// <summary>
        /// Class A
        /// </summary>
        public class ClassA
        {
            public virtual void XXX()
            {
                Console.WriteLine("ClassA XXX");
            }
        }
    
        /// <summary>
        /// ClassB
        /// </summary>
        public class ClassB:ClassA 
        {
            public override void XXX()
            {
                Console.WriteLine("ClassB XXX");
            }
        }
    
        /// <summary>
        /// Class C
        /// </summary>
        public class ClassC : ClassB
        {
            public virtual new void XXX()
            {
                Console.WriteLine("ClassC XXX");
            }
        }
    
        /// <summary>
        /// Class D
        /// </summary>
        public class ClassD : ClassC
        {
            public override void XXX()
            {
                Console.WriteLine("ClassD XXX");
            }
        }
    
        /// <summary>
        /// Program: used to execute the method.
        /// Contains Main method.
        /// </summary>
        public class Program
        {
            private static void Main(string[] args)
            {
                ClassA a = new ClassD();
                ClassB b = new ClassD();
                ClassC c=new ClassD();
                ClassD d=new ClassD();
               
                a.XXX();
                b.XXX();
                c.XXX();
                d.XXX();
    
                Console.ReadKey();
            }
        }

    输出 隐藏,复制Code

    ClassB XXX
    ClassB XXX
    ClassD XXX
    ClassD XXX

    解释 最后一个解释虚拟和覆盖会有点复杂。 ClassB XXX,第一个输出语句的结果a.XXX();。我们有XXX标志着类ClassA虚拟方法。因此,当使用新的关键字,我们现在继续ClassB类而不是ClassD如前所述。这里,XXX以来覆盖和c#知道类ClassC继承这个函数XXX。班上ClassC,因为它被标记为新的c#将ClassD回去不进行进一步的类。最后从ClassB类XXX被调用方法如上所示的输出。 如果我们改变方法在课堂上XXX ClassC覆盖,然后c#将继续类ClassD和调用的XXX类ClassD覆盖ClassC的XXX。 隐藏,复制Code

    /// <summary>
    /// Class C
    /// </summary>
    public class ClassC : ClassB
    {
        public override void XXX()
        {
            Console.WriteLine("ClassC XXX");
        }
    }
    

    从XXX移除覆盖类ClassD和方法会调用类ClassC作为默认是新的。 当我们谈论对象b,一切似乎类似于对象,因为它覆盖类ClassA的XXX。 当我们恢复默认值,让我们看一看第三行。对象c ClassC的样子。在课堂上ClassC, XXX()是新的,因此它没有连接与早些时候XXX方法。在课堂上ClassD,我们覆盖的XXX类ClassC的XXX ClassD调用。只是删除重写,然后它会从类ClassC调用。对象d不遵循任何上述协议的等号的两边都是相同的数据类型。 记住:一个覆盖方法是一种方法,包括覆盖修饰符。这引入了一种新的实现方法。我们不能使用修饰符如新,静态或虚拟覆盖。但抽象是允许的。 另一个例子: 隐藏,收缩,复制Code

    /// <summary>
        /// Class A
        /// </summary>
        public class ClassA
        {
            public virtual void XXX()
            {
                Console.WriteLine("ClassA XXX");
            }
        }
    
        /// <summary>
        /// ClassB
        /// </summary>
        public class ClassB:ClassA 
        {
            public override void XXX()
            {
                base.XXX();
                Console.WriteLine("ClassB XXX");
            }
        }
    
        /// <summary>
        /// Class C
        /// </summary>
        public class ClassC : ClassB
        {
            public override void XXX()
            {
                base.XXX();
                Console.WriteLine("ClassC XXX");
            }
        }
    
        /// <summary>
        /// Class D
        /// </summary>
        public class ClassD : ClassC
        {
            public override void XXX()
            {
                Console.WriteLine("ClassD XXX");
            }
        }
    
        /// <summary>
        /// Program: used to execute the method.
        /// Contains Main method.
        /// </summary>
        public class Program
        {
            private static void Main(string[] args)
            {
                ClassA a = new ClassB();
                a.XXX();
                ClassB b = new ClassC();
                b.XXX();
                Console.ReadKey();
            }
        }

    输出 隐藏,复制Code

    ClassA XXX
    ClassB XXX
    ClassA XXX
    ClassB XXX
    ClassC XXX

    当我们使用保留字基地,我们可以访问基类的方法。无论XXX是否虚拟,它将被视为非虚拟的关键字。因此,基类XXX总是被称为。XXX是虚拟的对象已经知道。当它到达ClassB,它看到base.XXX(),因此它调用XXX ClassA的方法。但在第二种情况下,第一次去上课ClassC,这里所谓的基地。XXX。XXX ClassB类的方法,在返回调用方法类ClassA的XXX。 10. 无限循环的 隐藏,收缩,复制Code

    /// <summary>
        /// Class A
        /// </summary>
        public class ClassA
        {
            public virtual void XXX()
            {
                Console.WriteLine("ClassA XXX");
            }
        }
    
        /// <summary>
        /// ClassB
        /// </summary>
        public class ClassB:ClassA 
        {
            public override void XXX()
            {
                ((ClassA)this).XXX();
                Console.WriteLine("ClassB XXX");
            }
        }
    
       
        /// <summary>
        /// Program: used to execute the method.
        /// Contains Main method.
        /// </summary>
        public class Program
        {
            private static void Main(string[] args)
            {
                ClassA a = new ClassB();
                a.XXX();
               
            }
        }

    输出 错误:{无法计算表达式,因为当前线程的堆栈溢出状态。} 在这种情况下,没有铸造将停止无限循环。因此,尽管这是一个类被ClassA,它总是从ClassB类而不是ClassA叫XXX。所以我们没有输出。 11. 总结 让我们总结所有的点要记住我们在大文章。 在c#中,我们可以将一个对象的基类派生类而不是反之亦然。需要覆盖修饰符为派生类将首要任务和被要求的方法。这些修饰符像新的覆盖只能用于如果基类的虚拟方法。虚拟意味着基类给予允许我们调用派生类的方法,而不是基类。但是,我们必须添加修饰符覆盖如果我们必须调用派生类方法。如果基类对象声明方法虚拟和修饰符覆盖使用的派生类,派生类的方法将被调用。否则,将执行基类方法。因此,虚拟方法,数据类型创建仅在运行时决定。没有标记的所有方法与虚拟非虚拟的,将被调用的方法是在编译时决定,根据静态数据类型的对象。一个覆盖方法是一种方法,包括覆盖修饰符。这引入了一种新的实现方法。我们不能你se修饰符如新,静态或虚拟覆盖。但抽象是允许的。 12. 结论 长文章,我的读者建议我写短的文章,但我不能帮助我自己。我写在一个流除非我清楚我不希望停止整个概念。我的目的是分享每一个细节以一种简单的方式,所以,你开始爱OOP。然而在本文中,我试图分类在不同的章节标题的可读性。 在本文中,我们学会了运行时多态和继承的概念。我们覆盖了大部分的场景通过动手实验室。我们将会覆盖更多的话题在我即将到来的文章。随意写评论或查询。喜欢我的文章和速率如果以任何方式帮助你,这将使我快乐。快乐的编码。 我的其他系列文章: MVC: http://www.codeproject.com/Articles/620195/Learning-MVC-Part-Introduction-to-MVC-Architectu RESTful webapi: http://www.codeproject.com/Articles/990492/RESTful-Day-sharp-Enterprise-Level-Application 编码快乐! 本文转载于:http://www.diyabc.com/frontweb/news1933.html

  • 相关阅读:
    一个表缺失索引发的CPU资源瓶颈案例
    SQLServer 版本之八大方法搞清 "我是谁"
    DBA成长路线
    SQL Server2016升级前几点自检
    SQL Server 2016白皮书
    <译>通过PowerShell工具跨多台服务器执行SQL脚本
    /lib64/libc.so.6: version `GLIBC_2.17' not found
    /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found
    HGT高程数据文件格式解析
    DEM高程数据下载资源
  • 原文地址:https://www.cnblogs.com/Dincat/p/13456669.html
Copyright © 2020-2023  润新知