写在前面:
学生时代我们写程序什么是面向对象,继承封装多态。这到底是什么鬼,也直到我参加工作者半年来才知道,写的多了自然而然就顺畅的多。 半年前的我自认不凡,然后面试屡遭碰壁。也终于找到归宿,认识到诸多不足,半年来,或喜或忧或狂躁。跪一人为师,生死无关。叫一声佛祖,回头无岸。现在我从头开始捋一捋,整理整理!我们走的太远,往往忘了最开始的起点。
源头
一.封装
public class Users { public Users() { } //无参构造函数 protected string userName; //只在该类和派生类可访问,派生类即通过继承所产生的新类也就是子类下节讲到 internal string userPassword; //只在程序集内有效 protected internal string userrole; //是protected&internal 并集 很多人理解为交集 public string userNickName; //公共的 完全访问 private string userID; //私有修饰符只在对象类可访问 public string UserId { get { return this.userID; } //对该字段具有Read权限,访问权限 set { this.userID = value; } //对该字段具有Write权限,写入权限 }private Users() //无参构造函数 定义默认值 初始化变量 { userID = "001"; } private Users(string ID, string Note)//有参构造函数 传参初始化 { userID = ID; userNote = Note; } ~Users() { //Cleaning up code goes here //析构函数用来执行GC操作,处理善后。C# GC处理还不错,一般用不到。C++用到的更多 }}
二.继承
从编程角度出发可以让代码具有重用性,不用造成代码冗余,节省时间。一路火花带闪电的,嗖嗖的。
1.继承是具有可传递性的。如果C从B中派生,B又从A中派生,那么C不仅继承了B中声明的成员,同样也继承了A中的成员。(相当于你具有一部分你爷爷的基因)
2.派生类(即子类)应当是对基类的扩展。派生类可以添加新的成员,但不能删除已经继承的成员的定义。(你爸爸永远是你爸爸,程序不会让你证明你爸是你爸这种SB问题)
3.构造函数和析构函数不能被继承。除此之外的其它成员,无论是私有的还是公共的,都能被继承。基类中成员的修饰符只能决定派生类能否访问它们。(你爸爸的钱就是你的钱。你爸可以给你,但是你不能去拿)
4.派生类如果定义了与继承而来的成员同名的新成员,就可以覆盖已继承的成员。但这并不因为这派生类删除了这些成员,只是不能再访问这些成员。(你在腰上拉一刀买了肾6,装上一个土豆。肾是回不来了,土豆还能凑合用)
5.类可以定义虚文法、虚属性以及虚索引指示器,它的派生类能够重载这些成员,从而实现类可以展示出多态性。(下节讲到)
ex:
namespace TestOOP { using System; internal class Inherit { //Test Inherit } #region TestCode internal class A { private string AName; public void OutPutA(string i) { this.AName = i; Console.WriteLine("I am {0}", this.AName); } } internal class B : A { private int BName; public void OutPutB(int i, int j) { Console.WriteLine("When Sum i+j in the Class B {0}", i + j); } } internal class C : B { } #endregion }
class Program { static void Main(string[] args) { C c = new C(); c.OutPutB(5, 3); //C继承了B的方法传参调用OutputB() c.OutPutA("A"); //C传递性继承了A的方法调用OutPutA() Console.ReadLine(); } }
internal class C : B { public void OutPutB(int i, int j) { Console.WriteLine("When Sum i+j in the Class C(Override OutPutB in the Class C) {0}", i + j); } }
如下图所示:(重写之后不再调用Class B的函数)
三.多态
通过继承,一个类可以用作多种类型:可以用作它自己的类型、任何基类型,或者在实现接口时用作任何接口类型。这称为多态性。C# 中的每种类型都是多态的。类型可用作它们自己的类型或用作 Object 实例,因为任何类型都自动将Object 当作基类型。多态性不仅对派生类很重要,对基类也很重要。任何情况下,使用基类实际上都可能是在使用已强制转换为基类类型的派生类对象。基类的设计者可以预测到其基类中可能会在派生类中发生更改的方面。
当派生类从基类继承时,它会获得基类的所有方法、字段、属性和事件。面向对象的语言使用虚方法表达多态。若要更改基类的数据和行为,您有两种选择:可以使用新的派生成员替换基成员,或者可以重写虚拟的基成员。
使用新的派生成员替换基类的成员需要使用new 关键字。如果基类定义了一个方法、字段或属性,则 new 关键字用于在派生类中创建该方法、字段或属性的新定义。new 关键字放置在要替换的类成员的返回类型之前。
public class PolymorphismBase { public int age; private int id; public string name; public int Id { get { return this.id; } } public void TestProgram() { Console.WriteLine("Base Class!"); } } public class PolymorphismSubClass : PolymorphismBase { //new 关键字时,调用的是新的类成员而不是已被替换的基类成员。这些基类成员称为隐藏成员 public new int age; public new string name; public new int Id { get { return 0; } } public new void TestProgram() { Console.WriteLine("Sub Class!"); } }
static void Main(string[] args) { PolymorphismSubClass PSC = new PolymorphismSubClass(); PSC.TestProgram(); //如果将派生类的实例强制转换为基类的实例,就仍然可以调用隐藏类成员。 PolymorphismBase PB = (PolymorphismBase)PSC; PB.TestProgram(); Console.ReadLine(); }
为了使派生类的实例完全接替来自基类的类成员,基类必须将该成员声明为虚拟的。这是通过在该成员的返回类型之前添加 virtual 关键字来实现的。然后,派生类可以选择使用 override 关键字而不是 new,将基类实现替换为它自己的实现。
public class PolymorphismBase { public int age; private int id; public string name; public virtual int Id { get { return this.id; } } public virtual void TestProgram() { Console.WriteLine("Base Class Virtual!"); } } public class PolymorphismSubClass : PolymorphismBase { public new int age; public new string name; public override int Id { get { return 0; } } public override void TestProgram() { Console.WriteLine("Sub Class Override!"); } }
static void Main(string[] args) { PolymorphismSubClass PSC = new PolymorphismSubClass(); PSC.TestProgram(); PolymorphismBase PB = (PolymorphismBase)PSC; PB.TestProgram(); Console.ReadLine(); }
无论在派生类和最初声明虚拟成员的类之间已声明了多少个类,虚拟成员都将永远为虚拟成员。如果类 A 声明了一个虚拟成员,类 B 从 A 派生,类 C 从类 B 派生,则类 C 继承该虚拟成员,并且可以选择重写它,而不管类 B 是否为该成员声明了重写。
public class PolymorphismBase { public int age; private int id; public string name; public virtual int Id { get { return this.id; } } public virtual void TestProgram() { Console.WriteLine("Base Class Virtual!"); } } public class PolymorphismSubClass : PolymorphismBase { public new int age; public new string name; public override int Id { get { return 0; } } public override void TestProgram() { Console.WriteLine("Sub Class Override!"); } } public class PolymorphismSubsubClass : PolymorphismSubClass { public override void TestProgram() { Console.WriteLine("Sub-sub Class Override!"); } }
static void Main(string[] args) { PolymorphismSubsubClass PSSC = new PolymorphismSubsubClass(); PSSC.TestProgram(); Console.ReadLine(); }
派生类可以通过将重写声明为密封的来停止虚拟继承。这需要在类成员声明中将 sealed 关键字放在 override 关键字的前面。
public class PolymorphismBase { public int age; private int id; public string name; public virtual int Id { get { return this.id; } } public virtual void TestProgram() { Console.WriteLine("Base Class Virtual!"); } } public class PolymorphismSubClass : PolymorphismBase { public new int age; public new string name; public sealed override int Id { get { return 0; } } public sealed override void TestProgram() { Console.WriteLine("Sub Class Override!"); } //sealed Function TestProgram() 对从PolymorphismSubClass派生的任何类都不再是虚拟的。它对PolymorphismSubClass的实例仍然是虚拟的。即使将这些实例强制转换为类型PolymorphismBase } public class PolymorphismSubsubClass : PolymorphismSubClass { //派生类可以通过使用 new 关键字替换密封的方法 public new void TestProgram() { Console.WriteLine("Sub-sub Class new Function!"); } }
不过我们任然可以利用base基类关键字访问基类的方法:static void Main(string[] args) { //在此情况下,如果在PolymorphismSubsubClass中使用类型为PolymorphismSubsubClass的变量调用TestProgram,被调用的将是新的TestProgram。 PolymorphismSubsubClass PSSC = new PolymorphismSubsubClass(); PSSC.TestProgram(); Console.ReadLine(); }
public class PolymorphismBase { public int age; private int id; public string name; public virtual int Id { get { return this.id; } } public virtual void TestProgram() { Console.WriteLine("Base Class Virtual!"); } } public class PolymorphismSubClass : PolymorphismBase { public new int age; public new string name; public sealed override int Id { get { return 0; } } public override void TestProgram() { Console.WriteLine("Sub Class Override!"); } } public class PolymorphismSubsubClass : PolymorphismSubClass { //如果使用类型为PolymorphismSubClass或PolymorphismBase的变量访问PolymorphismSubsubClass的实例,对 TestProgram 的调用将遵循虚拟继承的规则。 //即以基类关键字(base)访问TestProgram public new void TestProgram() { base.TestProgram(); } }
static void Main(string[] args) { PolymorphismSubsubClass PSSC = new PolymorphismSubsubClass(); PSSC.TestProgram(); Console.ReadLine(); }
Attention:
建议虚拟成员在它们自己的实现中使用 base 来调用该成员的基类实现。允许基类行为发生使得派生类能够集中精力实现特定于派生类的行为。未调用基类实现时,由派生类负责使它们的行为与基类的行为兼容。