C#菜鸟之旅-----里氏替换

     这是第二次学习“里氏替换”,因为经过了小组的讨论和自己今天的研究,感觉对于这个理解更深刻了,于是在学习完之后立刻整理,希望大家可以从这篇博客中有新的收获。

      对于百度上“大话设计模式”书中对于“里氏替换”的概念都是:    

       “派生类(子类)对象能够替换其基类(父类)对象使用”   ,而且他们的功能并不会发生变化。  

        但是为什么子类就可以替换父类,而且整个程序的功能不会受到影响呢? 

        原因:   当我们写的关系满足继承的时候,父类中会存在非私有(非private)成员,这个时候,子类肯定是得到了父类的这些非私有成员(假设,父类的成员全部都是私有的,那么子类没办法从父类继承任何成员,(这里有的网友也说是被继承了,只不过是无法访问)),既然子类继承了父类的非私有成员,那么父类对象也就可以在子类对象中调用这些非私有成员。

        我们先来根据小杨老师看看他讲的“里氏替换”的四种转换的类型:

定义了一个父类 Person,俩个子类:分别是student  ,teacher  , 
Int num=10;
Double dou=num;


第一种:
Person P =new Teacher();

Teacher t =(Teacher) p   ;  //这是是强制转换
//如果 new的是子类 ,那么父类可以转换为子类  这样的是可以的

第二种:
Person p =new Person();
Student stu=(Student) p ;
  //如果new的是父类,那么在转换子类的时候是不可以的

第三种:

Person p =new Teacher()
Student stu=(student)p;
//结果报异常,new的虽然是子类,但是转的却是另外一个子类;
//即new 的子类 和 转换的子类不是同一个类。

第四种:
子类转换成父类的时候就不需要强制转换,隐氏转换就可以了
Student stu=new student()
Person p =stu;
p.Show();
Console.readkey();
 
不会出现错误

通过上面小杨老师的讲解我们能够很清晰的清楚,在什么情况下我们才可以将父类替换成子类---或者说是用子类来替换父类。

下面我们再来通过一个例子来研究一下“里氏替换”:

class Program
    {
        static void Main(string[] args)
        {
            Person p = new Person();

            Person p1 = new Student();

            Console.ReadKey();
        }
    }

    class Person
    {
    //父类的私有成员
    private int nAge;


        public Person()
        {
            Console.WriteLine("我是Person构造函数,我是一个人!");
        }

        public void Say()
        {
            Console.WriteLine("我是一个人!");
        }

    }

    class Student : Person
    {
        public Student()
        {
            Console.WriteLine("我是Student构造函数,我是一个学生!");
        }

        public void SayStude()
        {
            Console.WriteLine("我是一个学生!");
        }
    }

    class SeniorStudent : Student
    {
        public SeniorStudent()
        {
            Console.WriteLine("我是SeniorStudent构造函数,我是一个高中生!");
        }
        public  void SaySenior()
        {
            Console.WriteLine("我是一个高中生!");
        }
    }

运行后的结果是:

然后我们在Main()函数中添加一些代码其他的地方不改变:

static void Main(string[] args)
        {
            Person p = new Person();
            p.Say();
  
            Person p1 = new Student();
            p1.Say();
            Console.ReadKey();
        }

继续运行,结果是:

而且在我输入代码的过程中,一个细节我发现,当我输入p.的时候,它后面的方法只有say,说明父类只可以访问父类的方法

在经过了 

person p1=new student(); 之后 输入p1.的时候后面也只显示 say 方法。

 所以这里就满足了里氏替换原则,子类的student 对象替换了父类person 对象的位置

二,虚方法中的里氏替换。

虚方法: 使用virtual关键字修饰的方法,叫作虚方法(一般都是在父类当中)

下面看一段关于虚方法的代码:

namespace ConsoleApp45
{
    class Program
    {
        static void Main(string[] args)
        {
            Person p = new Person();
            p.Say();

            Person p1 = new Student();
            p1.Say();

            Student s = new Student();
            s.Say();
            Console.ReadKey();
        }
    }
    class Person
    {
        private int nAge;
        public Person()
        {
            Console.WriteLine("我是Person构造函数,我是一个人!");
        }

        //这里定义了一个虚方法
        public virtual void Say()
        {
            Console.WriteLine("我是一个人!");
        }

    }

    class Student : Person
    {
        //子类使用override关键字改写了父类的虚方法
        public override void Say()
        {
            Console.WriteLine("我是一个学生!");
        }
        public Student()
        {
            Console.WriteLine("我是Student构造函数,我是一个学生!");
        }

        public void SayStude()
        {
            Console.WriteLine("我是一个学生!");
        }
    }
}

最终结果显示:

从上面的结果中可以看出,第二个表达式满足里氏替换原则,p1.say()执行的本该是父类的方法,但是却执行了子类的say方法

这就是子类使用override关键字覆盖了父类的虚方法

 上面的这种情况是在父类的方法中写了“virtual” 同时子类中的方法也写了 override 

那么如果父类中用 virtual修饰之后,而子类没有重写该方法。结果会是怎么样呢?


namespace ConsoleApp45
{

    class Program
    {
        static void Main(string[] args)
        {

            Person p1 = new Student();
            p1.Say();
            Console.ReadKey();
        }
    }

    class Person
    {
        private int nAge;
        public Person()
        {
            Console.WriteLine("我是Person构造函数,我是一个人!");
        }

        //这里定义了一个虚方法
        public virtual void Say()
        {
            Console.WriteLine("我是一个人!");
        }

    }

    class Student : Person
    {
        //子类中没有出现override关键字修饰的方法


        public void SayStude()
        {
            Console.WriteLine("我是一个学生!");
        }
    }
}

结果显示:

所以,如果子类中找不到 override 方法,就会回到子类的父类去找是否有 virtual并执行

猜你喜欢

转载自blog.csdn.net/qq_30631063/article/details/85997672