C#面向对象编程之继承和多态

原创 2016-11-12 09:49:24 718
摘要:继承和多态*继承可以让class具有一种特殊的能力,即实现class本身定义的所有功能外,还可以对父类(或称为基类、超类)的某些属性和功能进行扩展,这样的类我们称之为子类(或派生类)。继承有如下的几个规则:1. 可传递性:如: C是B的子类,B是A的子类,那么C会同时继承B和A;(object为所有类的基类)2. 唯扩展性:子类应是对父类的扩展,而不能在子类除去父类里面的定义;3. 构造函数和析构

继承和多态

*继承可以让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,属性可以;

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

public class MyClass
    {
        private string[] _strArray;

        public MyClass(int length)
        {
            this._strArray = new string[length];
        }

        public string this[int index]
        {
            get
            {
                if (index < this._strArray.Length)
                {
                    return this._strArray[index];
                }
                return null;
            }
            set
            {
                if (index < this._strArray.Length)
                {
                    this._strArray[index] = value;
                }
            }
        }
    }
static void Main(string[] args)
        {
            MyClass myClass = new MyClass(3);
            myClass[0] = "A";
            myClass[1] = "B";
            myClass[2] = "C";

            Console.WriteLine(myClass[0]);
            Console.WriteLine(myClass[1]);
            Console.WriteLine(myClass[2]);

            Console.ReadLine();
        }

运行结果:
A
B
C

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

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

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

854917-20160102032743557-957294752.png

具体的实现代码:

public abstract class Creature
    {
        private string _spiece;

        public Creature(string spiece)
        {
            this._spiece = spiece;
        }

        public string Spiece
        {
            get { return this._spiece; }
        }

        public abstract void Breath();
    }
public class Animal : Creature
    {
        private bool? _sex;

        public Animal(string spiece)
            : base(spiece)
        {
            this._sex = null;
        }

        public bool? Sex
        {
            get { return _sex; }
        }

        public virtual void Run()
        {
            Console.WriteLine("I am running...");
        }

        public override void Breath()
        {
            Console.WriteLine("I am breathing by animal respiration...");
        }
    }
public class Monkey : Animal
    {
        public Monkey(string spiece)
            : base(spiece) { }

        public void ClimbTree()
        {
            Console.WriteLine("I am climbing tree...");
        }

        public override void Run()
        {
            Console.WriteLine("I am running with two legs, sometimes with four legs...");
        }

        public override void Breath()
        {
            Console.WriteLine("I am breathing with lung...");
        }
    }
public class Fish : Animal
    {
        public Fish(string spiece)
            : base(spiece) { }

        public override void Run()
        {
            Console.WriteLine("I am running in the water with fins...");
        }

        public override void Breath()
        {
            Console.WriteLine("I am breathing with cheek...");
        }
    }
public class Plant : Creature
    {
        public Plant(string spiece)
            : base(spiece) { }

        public override void Breath()
        {
            Console.WriteLine("I am breathing by plant respiration...");
        }
    }
public class Tree : Plant
    {
        public Tree(string spiece)
            : base(spiece) { }

        //重载Breath()内部调用base.Breath(),其实和不写没啥区别,这里只是想告诉大家本质是什么。
        public override void Breath()
        {
            base.Breath();
        }
    }

程序运行测试代码:

class Program
    {
        static void Main(string[] args)
        {
            Creature creature001 = new Animal("Animal");
            Console.WriteLine(creature001.Spiece);
            creature001.Breath();

            Console.WriteLine("—————————————————————————");

            Creature creature002 = new Plant("Plant");
            Console.WriteLine(creature002.Spiece);
            creature002.Breath();

            Console.WriteLine("—————————————————————————");

            Animal animal001 = new Animal("Animal", true);
            Console.WriteLine(animal001.Spiece);
            Console.WriteLine(string.Format("Spiece:{0}; Sex:{1}", animal001.Spiece, GetSexName(animal001.Sex)));
            animal001.Breath();
            animal001.Run();

            Console.WriteLine("—————————————————————————");

            Creature monkey001 = new Monkey("Monkey", true);
            Console.WriteLine(monkey001.Spiece);
            monkey001.Breath();

            Console.WriteLine("—————————————————————————");

            Animal animal002 = new Monkey("Monkey", false);
            Console.WriteLine(animal002.Spiece);
            Console.WriteLine(string.Format("Spiece:{0}; Sex:{1}", animal002.Spiece, GetSexName(animal002.Sex)));
            animal002.Breath();
            animal002.Run();

            Console.WriteLine("—————————————————————————");

            Creature fish001 = new Fish("Fish", true);
            Console.WriteLine(fish001.Spiece);
            monkey001.Breath();

            Console.WriteLine("—————————————————————————");

            Animal fish002 = new Fish("Fish", true);
            Console.WriteLine(fish001.Spiece);
            Console.WriteLine(string.Format("Spiece:{0}; Sex:{1}", fish002.Spiece, GetSexName(fish002.Sex)));
            fish002.Breath();
            fish002.Run();

            Console.WriteLine("—————————————————————————");

            Animal animal004 = new Monkey("Monkey", false);
            Console.WriteLine(animal004.Spiece);
            Console.WriteLine(string.Format("Spiece:{0}; Sex:{1}", animal004.Spiece, GetSexName(animal004.Sex)));
            animal002.Breath();
            animal002.Run();

            Console.WriteLine("—————————————————————————");

            Monkey jack = new Monkey("Monkey", true);
            Console.WriteLine(jack.Spiece);
            Console.WriteLine(string.Format("Spiece:{0}; Sex:{1}", jack.Spiece, GetSexName(jack.Sex)));
            jack.Breath();
            jack.Run();
            jack.ClimbTree();

            Console.ReadLine();
        }

        private static string GetSexName(bool? value)
        {
            string sexName = null;
            if (value == null)
            {
                sexName = "undefined";
            }
            else
            {
                sexName = value.Value ? "male" : "female";
            }
            return sexName;
        }
    }

运行结果:

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抽象类。

如此,代码如下:

public interface IDraw
    {
        void DrawLine();

        void DrawCircle();

        void DrawRectangle();
    }
public abstract class Drawer : IDraw
    {
        private string _name;

        public Drawer(string name)
        {
            this._name = name;
        }

        public string Name
        {
            get
            {
                return this._name;
            }
        }

        public abstract void DrawLine();

        public abstract void DrawCircle();

        public abstract void DrawRectangle();
    }
//印象画派画家
    public class ImpressionistDrawer : Drawer
    {
        public ImpressionistDrawer(string name)
            : base(name) { }

        public override void DrawLine()
        {
            Console.WriteLine(string.Format("The impressionist drawer:{0} is drawing a line with pen.", this.Name));
        }

        public override void DrawCircle()
        {
            Console.WriteLine(string.Format("The impressionist drawer:{0} is drawing a circle with pen.", this.Name));
        }

        public override void DrawRectangle()
        {
            Console.WriteLine(string.Format("The impressionist drawer:{0} is drawing a rectangle with pen.", this.Name));
        }
    }
//写实主义画派画家
    public class RealismDrawer : Drawer
    {
        public RealismDrawer(string name)
            : base(name) { }

        public override void DrawLine()
        {
            Console.WriteLine(string.Format("The realism drawer:{0} is drawing a line with pencil.", this.Name));
        }

        public override void DrawCircle()
        {
            Console.WriteLine(string.Format("The realism drawer:{0} is drawing a circle with pencil.", this.Name));
        }

        public override void DrawRectangle()
        {
            Console.WriteLine(string.Format("The realism drawer:{0} is drawing a rectangle with pencil.", this.Name));
        }
    }

调用:

static void Main(string[] args)
        {
            IDraw draw001 = new RealismDrawer("莫柰");
            draw001.DrawCircle();
            draw001.DrawLine();
            draw001.DrawRectangle();

            Console.WriteLine();

            IDraw draw002 = new ImpressionistDrawer("弗洛伊德");
            draw002.DrawCircle();
            draw002.DrawLine();
            draw002.DrawRectangle();

            Console.ReadLine();
        }

运行结果:

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

public interface ILive
    {
        void EatRice();

        void Sleep();

        void BeatDouDou();
    }
public abstract class Drawer : IDraw, ILive
    {
        private string _name;

        public Drawer(string name)
        {
            this._name = name;
        }

        #region IDraw
        public string Name
        {
            get
            {
                return this._name;
            }
        }

        public abstract void DrawLine();

        public abstract void DrawCircle();

        public abstract void DrawRectangle();

        #endregion

        #region ILive

        public abstract void EatRice();

        public abstract void Sleep();

        public abstract void BeatDouDou();

        #endregion
    }
public ImpressionistDrawer(string name)
            : base(name) { }

        public override void DrawLine()
        {
            Console.WriteLine(string.Format("The impressionist drawer:{0} is drawing a line with pen.", this.Name));
        }

        public override void DrawCircle()
        {
            Console.WriteLine(string.Format("The impressionist drawer:{0} is drawing a circle with pen.", this.Name));
        }

        public override void DrawRectangle()
        {
            Console.WriteLine(string.Format("The impressionist drawer:{0} is drawing a rectangle with pen.", this.Name));
        }

        public override void EatRice()
        {
            Console.WriteLine(string.Format("The impressionist drawer:{0} is eating rice.", this.Name));
        }

        public override void Sleep()
        {
            Console.WriteLine(string.Format("The impressionist drawer:{0} is sleeping.", this.Name));
        }

        public override void BeatDouDou()
        {
            Console.WriteLine(string.Format("The impressionist drawer:{0} is beating DouDou.", this.Name));
        }
    }
public class RealismDrawer : Drawer
    {
        public RealismDrawer(string name)
            : base(name) { }

        public override void DrawLine()
        {
            Console.WriteLine(string.Format("The realism drawer:{0} is drawing a line with pencil.", this.Name));
        }

        public override void DrawCircle()
        {
            Console.WriteLine(string.Format("The realism drawer:{0} is drawing a circle with pencil.", this.Name));
        }

        public override void DrawRectangle()
        {
            Console.WriteLine(string.Format("The realism drawer:{0} is drawing a rectangle with pencil.", this.Name));
        }

        public override void EatRice()
        {
            Console.WriteLine(string.Format("The realism drawer:{0} is eating rice.", this.Name));
        }

        public override void Sleep()
        {
            Console.WriteLine(string.Format("The realism drawer:{0} is sleeping.", this.Name));
        }

        public override void BeatDouDou()
        {
            Console.WriteLine(string.Format("The realism drawer:{0} is beating DouDou.", this.Name));
        }
    }

调用:

static void Main(string[] args)
        {
            IDraw drawer001 = new RealismDrawer("莫柰");
            drawer001.DrawCircle();
            drawer001.DrawLine();
            drawer001.DrawRectangle();

            Console.WriteLine();

            IDraw drawer002 = new ImpressionistDrawer("弗洛伊德");
            drawer002.DrawCircle();
            drawer002.DrawLine();
            drawer002.DrawRectangle();

            Console.WriteLine();

            ILive drawer003 = new RealismDrawer("莫柰");
            drawer003.EatRice();
            drawer003.Sleep();
            drawer003.BeatDouDou();

            Console.WriteLine();

            ILive drawer004 = new RealismDrawer("弗洛伊德");
            drawer004.EatRice();
            drawer004.Sleep();
            drawer004.BeatDouDou();

            Console.ReadLine();
        }

运行结果:

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.


发布手记

热门词条