• 3. 第一章:C#面向对象编程之继承和多态


    第一章:C#面向对象编程

     

    第三节:继承和多态

    *继承可以让class具有一种特殊的能力,即实现class本身定义的所有功能外,还可以对父类(或称为基类、超类)的某些属性和功能进行扩展,这样的类我们称之为子类(或派生类)。

    继承有如下的几个规则:

    1. 可传递性:

    如: C是B的子类,B是A的子类,那么C会同时继承B和A;(object为所有类的基类)

    2. 唯扩展性:

    子类应是对父类的扩展,而不能在子类除去父类里面的定义;

    3. 构造函数和析构函数不能被继承:

    除去构造函数和析构函数不能被继承,其他的成员都能被继承(注意区别:能被继承和能被访问,是两个概念)

    4. 重载屏蔽性:

    如果子类定义了和父类成员同名的新成员,那么会执行重载和覆盖逻辑。但要明白的是,这样做,并不是删除了父类的这些成员,而是不能再访问这些被重载和覆盖的成员而已。

    5. 子类可以从父类的虚方法、虚属性以及虚索引器进行重载(即多态)

    我们可以借用override关键字对父类的虚方法、虚属性以及虚索引器进行重载;

    同时,我们也可以借用override关键字对抽象父类的抽象方法进行重载。

      abstract和virtural的区别:

        (1) abstract可以修饰class以及abstract class内部的函数、属性和索引器;而virtual不可以修饰class;

        (2) abstract修饰内部的函数、属性和索引器的时候,必须在abstract class才可以;而且abstract函数、属性和索引器不可以在abstract class里面有实现,但virtual必须要有实现。

        (3) virtual既可以修饰abstract class里面的函数、属性和索引器,也可以修饰一般class里面的函数、属性和索引器;

      *基础知识扩展:什么是索引器?

        索引器允许类或者结构的实例按照与数组相同的方式进行索引取值,索引器与属性类似,不同的是索引器的访问是带参的。

        A. 索引器和数组比较:

          (1)索引器的索引值(Index)类型不受限制;

          (2)索引器允许重载;

          (3)索引器不是一个变量;

        B. 索引器和属性的不同点

          (1)属性以名称来标识,索引器以函数形式标识;

          (2)索引器可以被重载,属性不可以;

          (3)索引器不能声明为static,属性可以;

        下面一个简单的例子可见一斑:

     1     public class MyClass
     2     {
     3         private string[] _strArray;
     4 
     5         public MyClass(int length)
     6         {
     7             this._strArray = new string[length];
     8         }
     9 
    10         public string this[int index]
    11         {
    12             get
    13             {
    14                 if (index < this._strArray.Length)
    15                 {
    16                     return this._strArray[index];
    17                 }
    18                 return null;
    19             }
    20             set
    21             {
    22                 if (index < this._strArray.Length)
    23                 {
    24                     this._strArray[index] = value;
    25                 }
    26             }
    27         }
    28     }
     1         static void Main(string[] args)
     2         {
     3             MyClass myClass = new MyClass(3);
     4             myClass[0] = "A";
     5             myClass[1] = "B";
     6             myClass[2] = "C";
     7 
     8             Console.WriteLine(myClass[0]);
     9             Console.WriteLine(myClass[1]);
    10             Console.WriteLine(myClass[2]);
    11 
    12             Console.ReadLine();
    13         }

    运行结果:
    A
    B
    C

    6. 子类只能继承一个父类(class),而可以继承多个接口(interface)(多重继承)

    *多态性:同一操作作用于不同的类的实例,将产生不同的执行结果,即不同类的对象收到相同的消息时,得到不同的结果。

    下图所示的类之间继承关系和多态用法,可以让大家更好了解这些概念的意义:

    具体的实现代码:

     1     public abstract class Creature
     2     {
     3         private string _spiece;
     4 
     5         public Creature(string spiece)
     6         {
     7             this._spiece = spiece;
     8         }
     9 
    10         public string Spiece
    11         {
    12             get { return this._spiece; }
    13         }
    14 
    15         public abstract void Breath();
    16     }
     1     public class Animal : Creature
     2     {
     3         private bool? _sex;
     4 
     5         public Animal(string spiece)
     6             : base(spiece)
     7         {
     8             this._sex = null;
     9         }
    10 
    11         public bool? Sex
    12         {
    13             get { return _sex; }
    14         }
    15 
    16         public virtual void Run()
    17         {
    18             Console.WriteLine("I am running...");
    19         }
    20 
    21         public override void Breath()
    22         {
    23             Console.WriteLine("I am breathing by animal respiration...");
    24         }
    25     }
     1     public class Monkey : Animal
     2     {
     3         public Monkey(string spiece)
     4             : base(spiece) { }
     5 
     6         public void ClimbTree()
     7         {
     8             Console.WriteLine("I am climbing tree...");
     9         }
    10 
    11         public override void Run()
    12         {
    13             Console.WriteLine("I am running with two legs, sometimes with four legs...");
    14         }
    15 
    16         public override void Breath()
    17         {
    18             Console.WriteLine("I am breathing with lung...");
    19         }
    20     }
     1     public class Fish : Animal
     2     {
     3         public Fish(string spiece)
     4             : base(spiece) { }
     5 
     6         public override void Run()
     7         {
     8             Console.WriteLine("I am running in the water with fins...");
     9         }
    10 
    11         public override void Breath()
    12         {
    13             Console.WriteLine("I am breathing with cheek...");
    14         }
    15     }
     1     public class Plant : Creature
     2     {
     3         public Plant(string spiece)
     4             : base(spiece) { }
     5 
     6         public override void Breath()
     7         {
     8             Console.WriteLine("I am breathing by plant respiration...");
     9         }
    10     }
     1     public class Tree : Plant
     2     {
     3         public Tree(string spiece)
     4             : base(spiece) { }
     5 
     6         //重载Breath()内部调用base.Breath(),其实和不写没啥区别,这里只是想告诉大家本质是什么。
     7         public override void Breath()
     8         {
     9             base.Breath();
    10         }
    11     }

    程序运行测试代码:

     1     class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             Creature creature001 = new Animal("Animal");
     6             Console.WriteLine(creature001.Spiece);
     7             creature001.Breath();
     8 
     9             Console.WriteLine("—————————————————————————");
    10 
    11             Creature creature002 = new Plant("Plant");
    12             Console.WriteLine(creature002.Spiece);
    13             creature002.Breath();
    14 
    15             Console.WriteLine("—————————————————————————");
    16 
    17             Animal animal001 = new Animal("Animal", true);
    18             Console.WriteLine(animal001.Spiece);
    19             Console.WriteLine(string.Format("Spiece:{0}; Sex:{1}", animal001.Spiece, GetSexName(animal001.Sex)));
    20             animal001.Breath();
    21             animal001.Run();
    22 
    23             Console.WriteLine("—————————————————————————");
    24 
    25             Creature monkey001 = new Monkey("Monkey", true);
    26             Console.WriteLine(monkey001.Spiece);
    27             monkey001.Breath();
    28 
    29             Console.WriteLine("—————————————————————————");
    30 
    31             Animal animal002 = new Monkey("Monkey", false);
    32             Console.WriteLine(animal002.Spiece);
    33             Console.WriteLine(string.Format("Spiece:{0}; Sex:{1}", animal002.Spiece, GetSexName(animal002.Sex)));
    34             animal002.Breath();
    35             animal002.Run();
    36 
    37             Console.WriteLine("—————————————————————————");
    38 
    39             Creature fish001 = new Fish("Fish", true);
    40             Console.WriteLine(fish001.Spiece);
    41             monkey001.Breath();
    42 
    43             Console.WriteLine("—————————————————————————");
    44 
    45             Animal fish002 = new Fish("Fish", true);
    46             Console.WriteLine(fish001.Spiece);
    47             Console.WriteLine(string.Format("Spiece:{0}; Sex:{1}", fish002.Spiece, GetSexName(fish002.Sex)));
    48             fish002.Breath();
    49             fish002.Run();
    50 
    51             Console.WriteLine("—————————————————————————");
    52 
    53             Animal animal004 = new Monkey("Monkey", false);
    54             Console.WriteLine(animal004.Spiece);
    55             Console.WriteLine(string.Format("Spiece:{0}; Sex:{1}", animal004.Spiece, GetSexName(animal004.Sex)));
    56             animal002.Breath();
    57             animal002.Run();
    58 
    59             Console.WriteLine("—————————————————————————");
    60 
    61             Monkey jack = new Monkey("Monkey", true);
    62             Console.WriteLine(jack.Spiece);
    63             Console.WriteLine(string.Format("Spiece:{0}; Sex:{1}", jack.Spiece, GetSexName(jack.Sex)));
    64             jack.Breath();
    65             jack.Run();
    66             jack.ClimbTree();
    67 
    68             Console.ReadLine();
    69         }
    70 
    71         private static string GetSexName(bool? value)
    72         {
    73             string sexName = null;
    74             if (value == null)
    75             {
    76                 sexName = "undefined";
    77             }
    78             else
    79             {
    80                 sexName = value.Value ? "male" : "female";
    81             }
    82             return sexName;
    83         }
    84     }

    运行结果:

    Animal
    I am breathing by animal respiration...
    —————————————————————————
    Plant
    I am breathing by plant respiration...
    —————————————————————————
    Animal
    Spiece:Animal; Sex:male
    I am breathing by animal respiration...
    I am running...
    —————————————————————————
    Monkey
    I am breathing with lung...
    —————————————————————————
    Monkey
    Spiece:Monkey; Sex:female
    I am breathing with lung...
    I am running with two legs, sometimes with four legs...
    —————————————————————————
    Fish
    I am breathing with lung...
    —————————————————————————
    Fish
    Spiece:Fish; Sex:male
    I am breathing with cheek...
    I am running in the water with fins...
    —————————————————————————
    Monkey
    Spiece:Monkey; Sex:female
    I am breathing with lung...
    I am running with two legs, sometimes with four legs...
    —————————————————————————
    Monkey
    Spiece:Monkey; Sex:male
    I am breathing with lung...
    I am running with two legs, sometimes with four legs...
    I am climbing tree...

    *多重继承

    类和接口都可以继承接口,而且可以继承不止一个接口。

    需求:

    IDraw接口,定义DrawLine、DrawCircle和DrawRectangle方法;

    Drawer,定义为抽象类,实现IDraw接口,附加属性Name;

    ImpressionistDrawer(印象画派画家)类,继承Drawer抽象类;

    RealismDrawer(写实主义画派画家)类,继承Drawer抽象类。

    如此,代码如下:

    1     public interface IDraw
    2     {
    3         void DrawLine();
    4 
    5         void DrawCircle();
    6 
    7         void DrawRectangle();
    8     }
     1     public abstract class Drawer : IDraw
     2     {
     3         private string _name;
     4 
     5         public Drawer(string name)
     6         {
     7             this._name = name;
     8         }
     9 
    10         public string Name
    11         {
    12             get
    13             {
    14                 return this._name;
    15             }
    16         }
    17 
    18         public abstract void DrawLine();
    19 
    20         public abstract void DrawCircle();
    21 
    22         public abstract void DrawRectangle();
    23     }
     1     //印象画派画家
     2     public class ImpressionistDrawer : Drawer
     3     {
     4         public ImpressionistDrawer(string name)
     5             : base(name) { }
     6 
     7         public override void DrawLine()
     8         {
     9             Console.WriteLine(string.Format("The impressionist drawer:{0} is drawing a line with pen.", this.Name));
    10         }
    11 
    12         public override void DrawCircle()
    13         {
    14             Console.WriteLine(string.Format("The impressionist drawer:{0} is drawing a circle with pen.", this.Name));
    15         }
    16 
    17         public override void DrawRectangle()
    18         {
    19             Console.WriteLine(string.Format("The impressionist drawer:{0} is drawing a rectangle with pen.", this.Name));
    20         }
    21     }
     1     //写实主义画派画家
     2     public class RealismDrawer : Drawer
     3     {
     4         public RealismDrawer(string name)
     5             : base(name) { }
     6 
     7         public override void DrawLine()
     8         {
     9             Console.WriteLine(string.Format("The realism drawer:{0} is drawing a line with pencil.", this.Name));
    10         }
    11 
    12         public override void DrawCircle()
    13         {
    14             Console.WriteLine(string.Format("The realism drawer:{0} is drawing a circle with pencil.", this.Name));
    15         }
    16 
    17         public override void DrawRectangle()
    18         {
    19             Console.WriteLine(string.Format("The realism drawer:{0} is drawing a rectangle with pencil.", this.Name));
    20         }
    21     }

    调用:

     1         static void Main(string[] args)
     2         {
     3             IDraw draw001 = new RealismDrawer("莫柰");
     4             draw001.DrawCircle();
     5             draw001.DrawLine();
     6             draw001.DrawRectangle();
     7 
     8             Console.WriteLine();
     9 
    10             IDraw draw002 = new ImpressionistDrawer("弗洛伊德");
    11             draw002.DrawCircle();
    12             draw002.DrawLine();
    13             draw002.DrawRectangle();
    14 
    15             Console.ReadLine();
    16         }

    运行结果:

    The realism drawer:莫柰 is drawing a circle with pencil.

    The realism drawer:莫柰 is drawing a line with pencil.

    The realism drawer:莫柰 is drawing a rectangle with pencil.

    The impressionist drawer:弗洛伊德 is drawing a circle with pen.

    The impressionist drawer:弗洛伊德 is drawing a line with pen.

    The impressionist drawer:弗洛伊德 is drawing a rectangle with pen.

    扩展一下,比方说:这些画家除了要画画之外,一样都要吃饭睡觉打豆豆,怎么处理呢?

    我们当然不能把吃饭睡觉打豆豆归为IDraw这个intercace里面,因为这完全是不相干的行为呀!于是,我们考虑新建一个interface

    1     public interface ILive
    2     {
    3         void EatRice();
    4 
    5         void Sleep();
    6 
    7         void BeatDouDou();
    8     }
     1     public abstract class Drawer : IDraw, ILive
     2     {
     3         private string _name;
     4 
     5         public Drawer(string name)
     6         {
     7             this._name = name;
     8         }
     9 
    10         #region IDraw
    11         public string Name
    12         {
    13             get
    14             {
    15                 return this._name;
    16             }
    17         }
    18 
    19         public abstract void DrawLine();
    20 
    21         public abstract void DrawCircle();
    22 
    23         public abstract void DrawRectangle();
    24 
    25         #endregion
    26 
    27         #region ILive
    28 
    29         public abstract void EatRice();
    30 
    31         public abstract void Sleep();
    32 
    33         public abstract void BeatDouDou();
    34 
    35         #endregion
    36     }
     1         public ImpressionistDrawer(string name)
     2             : base(name) { }
     3 
     4         public override void DrawLine()
     5         {
     6             Console.WriteLine(string.Format("The impressionist drawer:{0} is drawing a line with pen.", this.Name));
     7         }
     8 
     9         public override void DrawCircle()
    10         {
    11             Console.WriteLine(string.Format("The impressionist drawer:{0} is drawing a circle with pen.", this.Name));
    12         }
    13 
    14         public override void DrawRectangle()
    15         {
    16             Console.WriteLine(string.Format("The impressionist drawer:{0} is drawing a rectangle with pen.", this.Name));
    17         }
    18 
    19         public override void EatRice()
    20         {
    21             Console.WriteLine(string.Format("The impressionist drawer:{0} is eating rice.", this.Name));
    22         }
    23 
    24         public override void Sleep()
    25         {
    26             Console.WriteLine(string.Format("The impressionist drawer:{0} is sleeping.", this.Name));
    27         }
    28 
    29         public override void BeatDouDou()
    30         {
    31             Console.WriteLine(string.Format("The impressionist drawer:{0} is beating DouDou.", this.Name));
    32         }
    33     }
     1     public class RealismDrawer : Drawer
     2     {
     3         public RealismDrawer(string name)
     4             : base(name) { }
     5 
     6         public override void DrawLine()
     7         {
     8             Console.WriteLine(string.Format("The realism drawer:{0} is drawing a line with pencil.", this.Name));
     9         }
    10 
    11         public override void DrawCircle()
    12         {
    13             Console.WriteLine(string.Format("The realism drawer:{0} is drawing a circle with pencil.", this.Name));
    14         }
    15 
    16         public override void DrawRectangle()
    17         {
    18             Console.WriteLine(string.Format("The realism drawer:{0} is drawing a rectangle with pencil.", this.Name));
    19         }
    20 
    21         public override void EatRice()
    22         {
    23             Console.WriteLine(string.Format("The realism drawer:{0} is eating rice.", this.Name));
    24         }
    25 
    26         public override void Sleep()
    27         {
    28             Console.WriteLine(string.Format("The realism drawer:{0} is sleeping.", this.Name));
    29         }
    30 
    31         public override void BeatDouDou()
    32         {
    33             Console.WriteLine(string.Format("The realism drawer:{0} is beating DouDou.", this.Name));
    34         }
    35     }

    调用:

     1         static void Main(string[] args)
     2         {
     3             IDraw drawer001 = new RealismDrawer("莫柰");
     4             drawer001.DrawCircle();
     5             drawer001.DrawLine();
     6             drawer001.DrawRectangle();
     7 
     8             Console.WriteLine();
     9 
    10             IDraw drawer002 = new ImpressionistDrawer("弗洛伊德");
    11             drawer002.DrawCircle();
    12             drawer002.DrawLine();
    13             drawer002.DrawRectangle();
    14 
    15             Console.WriteLine();
    16 
    17             ILive drawer003 = new RealismDrawer("莫柰");
    18             drawer003.EatRice();
    19             drawer003.Sleep();
    20             drawer003.BeatDouDou();
    21 
    22             Console.WriteLine();
    23 
    24             ILive drawer004 = new RealismDrawer("弗洛伊德");
    25             drawer004.EatRice();
    26             drawer004.Sleep();
    27             drawer004.BeatDouDou();
    28 
    29             Console.ReadLine();
    30         }

    运行结果:

    The realism drawer:莫柰 is drawing a circle with pencil.

    The realism drawer:莫柰 is drawing a line with pencil.

    The realism drawer:莫柰 is drawing a rectangle with pencil.

    The impressionist drawer:弗洛伊德 is drawing a circle with pen.

    The impressionist drawer:弗洛伊德 is drawing a line with pen.

    The impressionist drawer:弗洛伊德 is drawing a rectangle with pen.

    The realism drawer:莫柰 is eating rice.

    The realism drawer:莫柰 is sleeping.

    The realism drawer:莫柰 is beating DouDou.

    The realism drawer:弗洛伊德 is eating rice.

    The realism drawer:弗洛伊德 is sleeping.

    The realism drawer:弗洛伊德 is beating DouDou.

  • 相关阅读:
    css的继承问题
    js弹出层
    实现网页弹出框后背景不能滑动的效果
    vue的爬坑之路(四)之基于vuecli 动态添加iconfont的symbol方法
    vue的爬坑之路(五)之基于vuecli li列表的显示隐藏
    自定义复选框checkbox样式
    vue的爬坑之路(三)之基于vuecli的VueAwesomeSwiper轮播滑块插件的使用及常见问题
    iOS 开发学习总结
    (转载)iOS股票k线组件源码,支持其他图表类型
    iOS Objective C Memory management
  • 原文地址:https://www.cnblogs.com/Min-min/p/5094073.html
Copyright © 2020-2023  润新知