1. 介绍 我们学到了很多关于多态和继承。在这篇文章系列的OOP“跳水”,我们将讨论最热门的和令人兴奋的话题OOP在c#中,即抽象类。抽象类的概念是相同的任何其他语言,但在c#中我们以稍微不同的方式处理它。抽象类中发挥不同的和非常有趣的角色多态和继承。我们将涵盖所有方面的抽象类与我们的动手实验和理论解释输出我们得到什么。我们还将列表点记住文章的最后。 的必备条件 想知道,我们正在处理的第四部分我们的学习目标。现在我唯一的期望和我的读者享受系列。 2. 路线图 让我们回忆起我们的路线图: ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 潜水在OOP(第一天):多态和继承(早期绑定/编译时多态)潜水在OOP(第二天):多态和继承(继承)潜水OOP(第三天):多态和继承(动态绑定/运行时多态)潜水在OOP(第四天):多态和继承(关于抽象类在c#)潜水在OOP(第五天):都是用c#访问修饰符(公共/私人/保护/内部/密封/常量/只读的字段)潜水OOP(6天):理解枚举在c#中(一个实际的方法)深入OOP(第七天):用c#属性(一个实际的方法)深入OOP(8天):用c#索引器(一个实际的方法)潜水印锑OOP(9天):了解c#事件(Insight)学习c#(第十天):代表在c#中(一个实际的方法)学习c#(11天):c#事件(一个实际的方法) 3.抽象类 让我们从MSDN的定义: “abstract关键字使您能够创建类和类成员是不完整的,必须在派生类中实现。抽象类不能被实例化。一个抽象类的目的是提供一个共同的基类的定义,多个派生类可以共享。例如,一个类库可能定义一个抽象类,它作为参数的函数,并要求程序员使用库来提供自己的实现的类创建一个派生类。 抽象类也可以定义抽象方法。这是通过添加关键字实现抽象方法的返回类型。” 4. 抽象类的作用 添加一个控制台应用程序命名为“InheritanceAndPolymorphism”在你的Visual Studio。你会得到一个类命名程序。cs,只需添加一个名为ClassA的类。cs,注意ClassA应该标记为抽象的,和下面的代码ClassA.cs Program.cs: 隐藏,复制Code
using System; namespace InheritanceAndPolymorphism { public abstract class ClassA { } /// <summary> /// Program: used to execute the method. /// Contains Main method. /// </summary> public class Program { private static void Main(string[] args) { ClassA classA = new ClassA(); Console.ReadKey(); } } }
编译代码。 输出 隐藏,复制Code
Compile time error: Cannot create an instance of the abstract class or interface 'InheritanceAndPolymorphism.ClassA'
记住:我们不能使用新的关键字创建一个抽象类的对象。 现在我们去理解这个概念。没有力量能够阻止抽象关键字之前写一个类。它作为一个修饰符的类。我们不能使用新的关键字创建一个抽象类的对象。看来,类是无用的对我们我们不能用它来我们用来做其他的实用目的。 5. 非抽象方法定义在抽象类 让我们添加一些代码来抽象类: 隐藏,复制Code
/// <summary> /// Abstract class ClassA /// </summary> public abstract class ClassA { public int a; public void XXX() { } } /// <summary> /// Program: used to execute the method. /// Contains Main method. /// </summary> public class Program { private static void Main(string[] args) { ClassA classA = new ClassA(); Console.ReadKey(); } }
我们再次看到我们之前遇到的错误。再一次,它提醒我们不能使用新的如果我们已经使用一个抽象的修饰符。 6. 抽象类作为基类 现在让我们添加一个类: 隐藏,收缩,复制Code
/// <summary> /// Abstract class ClassA /// </summary> public abstract class ClassA { public int a; public void XXX() { } } /// <summary> /// Derived class. /// Class derived from abstract class ClassA /// </summary> public class ClassB:ClassA { } /// <summary> /// Program: used to execute the method. /// Contains Main method. /// </summary> public class Program { private static void Main(string[] args) { ClassB classB = new ClassB(); Console.ReadKey(); } }
我们没有错误吗?一个类可以从抽象类派生的。创建一个对象ClassB不给我们任何的错误。 记住:一个类可以派生自一个抽象类。 记住:一个对象的类派生自一个抽象类可以使用新创建。 注意:每一个代码片段写本文是尝试和测试。 7. 非抽象类的抽象方法声明 另一个场景: 隐藏,收缩,复制Code
/// <summary> /// Abstract class ClassA /// </summary> public abstract class ClassA { public int a; public void XXX() { } public void YYY(); } /// <summary> /// Derived class. /// Class derived from abstract class ClassA. /// </summary> public class ClassB:ClassA { } /// <summary> /// Program: used to execute the method. /// Contains Main method. /// </summary> public class Program { private static void Main(string[] args) { ClassB classB = new ClassB(); Console.ReadKey(); } }
我们只声明一个方法叫我们抽象类ClassA YYY()。 编译代码,我们得到: 输出 隐藏,复制Code
Compile time error: 'InheritanceAndPolymorphism.ClassA.YYY()' must declare a body because it is not marked abstract, extern, or partial
InheritanceAndPolymorphism是我用于我的控制台应用程序的命名空间可以忽略,不需要与逻辑混淆。 在上面的代码中,我们添加了一个抽象类中的方法声明。一个抽象方法表明,实际的定义或别的地方创建代码的方法。抽象类中声明的方法原型也必须声明为抽象按c#的规则。 8. 抽象类的抽象方法声明 只是让ClassA YYY()方法为抽象: 隐藏,收缩,复制Code
/// <summary> /// Abstract class ClassA /// </summary> public abstract class ClassA { public int a; public void XXX() { } abstract public void YYY(); } /// <summary> /// Derived class. /// Class derived from abstract class ClassA. /// </summary> public class ClassB:ClassA { } /// <summary> /// Program: used to execute the method. /// Contains Main method. /// </summary> public class Program { private static void Main(string[] args) { ClassB classB = new ClassB(); Console.ReadKey(); } }
欧tput 隐藏,复制Code
Compiler error: 'InheritanceAndPolymorphism.ClassB' does not implement inherited abstract member 'InheritanceAndPolymorphism.ClassA.YYY()'
要记住一点:如果我们将任何方法声明为抽象抽象类,那么它的责任是派生类提供的抽象方法,除非身体是抽象方法提供,我们就无法创造一个派生类的对象。 在上述场景中,我们宣布YYY()方法在ClassA文摘。ClassB源自ClassA以来,现在变得ClassB的责任提供的抽象方法,否则我们不能ClassB创建一个对象。 9. 派生类的抽象方法实现 现在提供的方法在ClassB YYY()。让我们看看会发生什么: 隐藏,收缩,复制Code
/// <summary> /// Abstract class ClassA /// </summary> public abstract class ClassA { public int a; public void XXX() { } abstract public void YYY(); } /// <summary> /// Derived class. /// Class derived from abstract class ClassA. /// </summary> public class ClassB:ClassA { public void YYY() { } } /// <summary> /// Program: used to execute the method. /// Contains Main method. /// </summary> public class Program { private static void Main(string[] args) { ClassB classB = new ClassB(); Console.ReadKey(); } }
现在一切都好,但没有?编译代码,我们得到: 输出 两个编译时错误: 隐藏,复制Code
Compile time error: 'InheritanceAndPolymorphism.ClassB' does not implement inherited abstract member 'InheritanceAndPolymorphism.ClassA.YYY()' Compile time warning: 'InheritanceAndPolymorphism.ClassB.YYY()' hides inherited member 'InheritanceAndPolymorphism.ClassA.YYY()'.
使当前成员覆盖,实现,添加覆盖关键字。否则添加新的关键字。 我们不断尝试编译的代码,但没有成功,直到现在。编译器错误也清楚表明,我们的基地和派生类都包含相同的方法叫YYY()。 如果派生类和基类包含的方法相同的名字,总是出现错误。唯一的方法来克服这个错误是派生类显式地添加修饰符覆盖的方法签名。我们已经讨论过这样的场景在我们之前的部分在OOP潜水系列的文章。 让我们添加覆盖关键字在派生类方法YYY()。 隐藏,收缩,复制Code
/// <summary> /// Abstract class ClassA /// </summary> public abstract class ClassA { public int a; public void XXX() { } abstract public void YYY(); } /// <summary> /// Derived class. /// Class derived from abstract class ClassA. /// </summary> public class ClassB:ClassA { public override void YYY() { } } /// <summary> /// Program: used to execute the method. /// Contains Main method. /// </summary> public class Program { private static void Main(string[] args) { ClassB classB = new ClassB(); Console.ReadKey(); } }
我们现在没有警告或错误吗? 10. 抽象方法实现派生类有不同的返回类型 记住:当我们覆盖an 抽象或virtual 派生类中的方法时,我们不能改变传递给它的参数或覆盖方法的返回类型。 让我们改变方法的返回类型YYY()在派生类: 隐藏,收缩,复制Code
/// <summary> /// Abstract class ClassA /// </summary> public abstract class ClassA { public int a; public void XXX() { } abstract public void YYY(); } /// <summary> /// Derived class. /// Class derived from abstract class ClassA. /// </summary> public class ClassB:ClassA { public override int YYY() { } } /// <summary> /// Program: used to execute the method. /// Contains Main method. /// </summary> public class Program { private static void Main(string[] args) { ClassB classB = new ClassB(); Console.ReadKey(); } }
我们改变了方法的返回类型YYY从空白到int在派生类。编译代码。 输出 隐藏,复制Code
Compile time error: 'InheritanceAndPolymorphism.ClassB.YYY()': return type must be 'void' to match overridden member 'InheritanceAndPolymorphism.ClassA.YYY()'
因此一个约束。 记住:An abstract 类意味着类是不完整的,不能直接使用。An abstract 类只能用作基类来自其他类。 让我们看看第二行中提到的实现“记住”, 隐藏,收缩,复制Code
/// <summary> /// Abstract class ClassA /// </summary> public abstract class ClassA { public int a; public void XXX() { } abstract public void YYY(); abstract public void YYY1(); abstract public void YYY2(); abstract public void YYY3(); } /// <summary> /// Derived class. /// Class derived from abstract class ClassA. /// </summary> public class ClassB:ClassA { public override void YYY() { } } /// <summary> /// Program: used to execute the method. /// Contains Main method. /// </summary> public class Program { private static void Main(string[] args) { ClassB classB = new ClassB(); Console.ReadKey(); } }
编译错误: 隐藏,复制Code
'InheritanceAndPolymorphism.ClassB' does not implement inherited abstract member 'InheritanceAndPolymorphism.ClassA.YYY3()' 'InheritanceAndPolymorphism.ClassB' does not implement inherited abstract member 'InheritanceAndPolymorphism.ClassA.YYY2()' 'InheritanceAndPolymorphism.ClassB' does not implement inherited abstract member 'InheritanceAndPolymorphism.ClassA.YYY1()'
如果我们在派生类中实现这三种方法,我们没有错误。 11. 抽象类中变量初始化 因此,正如前面看到的,我们得到一个错误,如果我们使用一个新的关键字在一个抽象类。如果我们不初始化一个变量在我们使用这样的一个抽象类,它会自动有一个默认值0就是编译器警告我们。我们可以初始化int变量ClassA我们希望的任何值。抽象类中的变量法类似于任何其他正常的类。 12. 抽象类的力量 当一个类仍然是不完整的,也就是说。,我们没有一些方法的代码,我们纪念那些抽象方法和抽象类标记。因此,我们可以编译我们班没有任何错误或拦截器。其他类可以来自我们的抽象类,但他们必须实现抽象,即。从抽象类,我们的完整方法。 文摘因此使我们能够编写代码类的一部分,并允许其他人(派生类)来完成剩下的代码。 13. 非抽象类的抽象方法 让我们看另一个代码块: 隐藏,收缩,复制Code
/// <summary> /// Abstract class ClassA /// </summary> public class ClassA { public int a; public void XXX() { } abstract public void YYY(); } /// <summary> /// Derived class. /// Class derived from abstract class ClassA. /// </summary> public class ClassB:ClassA { public override void YYY() { } } /// <summary> /// Program: used to execute the method. /// Contains Main method. /// </summary> public class Program { private static void Main(string[] args) { ClassB classB = new ClassB(); Console.ReadKey(); } }
编译代码。 输出 隐藏,复制Code
Compiler error: 'InheritanceAndPolymorphism.ClassA.YYY()' is abstract but it is contained in non-abstract class 'InheritanceAndPolymorphism.ClassA'
注意:每一个代码片段写本文是尝试和测试。 我们只是抽象的关键字从类ClassA删除。错误清楚地传达了一个消息,如果一个方法是抽象的类,然后类必须抽象。 要记住一点:如果一个类甚至一个抽象方法,那么也必须声明为抽象类。 记住:一个抽象方法也不能使用静态或虚拟等修饰符。 我们只能有一个抽象类中的抽象方法。任何类,来源于抽象类必须实现其抽象方法。默认情况下,修改新添加到派生类的方法,使它一个新的/不同的方法。 14. 抽象的基本方法 隐藏,收缩,复制Code
/// <summary> /// Abstract class ClassA /// </summary> public abstract class ClassA { public int a; public void XXX() { } abstract public void YYY(); } /// <summary> /// Derived class. /// Class derived from abstract class ClassA. /// </summary> public class ClassB:ClassA { public override void YYY() { base.YYY(); } } /// <summary> /// Program: used to execute the method. /// Contains Main method. /// </summary> public class Program { private static void Main(string[] args) { ClassB classB = new ClassB(); Console.ReadKey(); } }
输出 隐藏,复制Code
Compile time error : Cannot call an abstract base member: 'InheritanceAndPolymorphism.ClassA.YYY()'
我们不能调用方法YYY()从基类ClassA它不携带任何实现/代码以及它和也被声明为抽象。常识盛行?和c#当然不允许我们调用一个方法,不包含代码。 15. 抽象类的行为ing派生类和基类 让我们稍微修改一下我们的代码,并准备我们的类结构如下: 隐藏,收缩,复制Code
/// <summary> /// Base class ClassA /// </summary> public class ClassA { public virtual void XXX() { Console.WriteLine("ClassA XXX"); } } /// <summary> /// Derived abstract class. /// Class derived from base class ClassA. /// </summary> public abstract class ClassB:ClassA { public new abstract void XXX(); } public class ClassC:ClassB { public override void XXX() { System.Console.WriteLine("ClassC XXX"); } } /// <summary> /// Program: used to execute the method. /// Contains Main method. /// </summary> public class Program { private static void Main(string[] args) { ClassA classA = new ClassC(); ClassB classB = new ClassC(); classA.XXX(); classB.XXX(); } }
编译代码并运行。 输出 隐藏,复制Code
ClassA XXX ClassC XXX
我们创建了一个名为ClassA的非抽象基类,并向其添加了一个虚拟方法XXX。由于该方法是非抽象的,但标记为virtual,因此必须在其派生类中重写它。我们又添加了一个名为ClassB的类,并将其标记为abstract,请注意这个类是从ClassA派生出来的。因此这个类可以选择重写基类中标记为virtual的方法。但我们会做一些不同的,棘手的事情, 在这个派生类中,我们将XXX方法标记为新抽象,并且没有为这个方法提供任何人。现在怎么办呢?我们将再添加一个类ClassC,它将派生自ClassB。ClassC别无选择,只能重写方法XXX。因此,我们重写了类c中的方法XXX。 在main方法中,我们创建了两个对象:ClassA ClassA = new ClassC();ClassB = new ClassC(); 第一个对象看起来像ClassC,但是引用了ClassA,第二个对象看起来又像ClassC,但是引用了ClassB。 在类的情况下,xxx()肯定会首先查看类ClassA。在这里,它找到标记为virtual的方法XXX。在前面讨论运行时多态的文章中,我们已经使用了n次这种场景。然后c#将爬到class ClassB。在这里,令人震惊的是方法XXX()是抽象的,即。,方法XXX()没有代码或实现,而且它是一个标记为new的方法,因此切断了与基类的所有链接。流停止了,ClassA中的方法XXX()被执行。 在b.XXX()()的情况下,由于方法是新的,到基类的链接被破坏,我们别无选择,只能从ClassC调用方法,正如它所说的重载。 我们不能用抽象类ClassB中方法XXX()的关键字override替换修饰符new。 让我们用“new”替换ClassC中的覆盖修饰符,就像: 隐藏,复制Code
public class ClassC:ClassB { public new void XXX() { System.Console.WriteLine("ClassC XXX"); } }
输出 隐藏,复制Code
Compile time error: 'InheritanceAndPolymorphism.ClassC' does not implement inherited abstract member 'InheritanceAndPolymorphism.ClassB.XXX()'
该错误表明,由于方法XXX没有代码。记住,类ClassA的XXX()与类b和类c的XXX()没有任何关系。 还有一点要记住。 请记住:虚拟方法比非虚拟方法运行得慢。 16. 抽象类可以被密封吗? 让我们考虑一下最后这个问题。让我们用一个例子来测试一下。 隐藏,复制Code
/// <summary> /// sealed abstract class ClassA /// </summary> public sealed abstract class ClassA { public abstract void XXX() { Console.WriteLine("ClassA XXX"); } } /// <summary> /// Program: used to execute the method. /// Contains Main method. /// </summary> public class Program { private static void Main(string[] args) { } }
编译代码。 输出 隐藏,复制Code
Compile time error: 'InheritanceAndPolymorphism.ClassA': an abstract class cannot be sealed or static
我们需要记住两点。 注意:抽象类不能是密封类。 请记住:抽象类不能是静态类。 17. 点要记住 让我们总结一下需要记住的要点: 我们不能使用new关键字创建抽象类的对象。类可以从抽象类派生。派生自抽象类的类的对象可以使用new创建。如果我们在抽象类中声明任何方法是抽象的,那么派生类就有责任提供该抽象方法的主体,除非为该抽象方法提供了主体,否则我们不能创建该派生类的对象。当我们从派生类中重写一个抽象方法或一个虚拟方法时,我们不能改变传递给它的参数或被重写方法的返回类型。抽象类意味着这个类是不完整的,不能直接使用。抽象类只能用作派生其他类的基类。如果一个类只有一个抽象方法,那么这个类也必须声明为抽象。抽象方法也不能使用修饰符,如静态或虚拟。虚方法比非虚方法运行得慢。抽象类不能是密封类。抽象类不能是静态类。 18. 结论 通过本文,我们完成了对继承和多态性的理解。我们几乎涵盖了多态性和继承的所有方面。抽象类是我最喜欢的类之一,所以我只想分别使用它们。我希望我的读者也喜欢这篇文章,并学习了c#中的抽象类。 在我接下来的系列文章中,我们将通过完整的动手实践和大量的讨论来讨论c#方式下的其他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/news1949.html