C# 继承- 面向对象 - 继承

   

继承的特性:

        1、单根性:一个类只能继承于另外一个类,不能同时继承多个类

        2、传递性:子类的父类可以基于继承别的类,子类>父类>爷爷类>祖宗类,可以逐一传递祖宗类的属性和方法等,子类可以进行使用。

继承的好处:

        1、代码重用,把重复的代码封装起来,别的类使用的时候直接继承即可

        2、多态,通过里氏替换原则实现多态,增加程序的可扩展性和灵活性

一、继承的基本实现

Student person = new Student();
person.name = "张三";//继承父类的属性
person.sex = "男";//继承父类的属性
person.studentid = "001";
person.GetName();//继承父类的方法

Console.ReadKey();

/// <summary>
/// 人类
/// </summary>
class Person
{
    public string name { get; set; }
    public string sex { get; set; }

    public void GetName() {
        Console.WriteLine(name);
    }
}

/// <summary>
/// 学生类 继承Person类
/// </summary>
class Student:Person//通过:类名 继承别的类
{
    public string studentid { get; set; }
}

二、继承中构造函数问题

        构造函数是不能被继承的

        当一个子类继承父类之后,该子类中所有构造函数默认情况下,在自己被调用之前
 都会调用一下父类中的无参构造函数,此时父类中没有无参构造函数的情况下就会报错,例如,如下代码编译器就会爆出错误。

       

StudentInfo  StudentInfo = new StudentInfo("tom","合肥",1);
Console.ReadKey();

class PersonInfo 
{
    /// <summary>
    /// 父类中的构造函数
    /// </summary>
    /// <param name="_Name"></param>
    /// <param name="_Address"></param>
    public PersonInfo(string _Name, string _Address)
    {
        this.Name = _Name;
        this.Address = _Address;
    }


    public string Name { get; set; }
    public string Address { get; set; }
}

class StudentInfo:PersonInfo
{
    /// <summary>
    /// 子类中的构造函数
    /// 
    /// 这个时候编译器会报错,当一个子类继承父类之后,该子类中所有构造函数默认情况下,在自己被调用之前
    /// 都会调用一下父类中的无参构造函数,此时父类中没有无参构造函数的情况下就会报错
    /// </summary>>
    public StudentInfo(string _Name, string _Address, int _Id)
    { 
        this.Name = _Name;
        this.Address = _Address;
        this.Id = _Id;
    }

    public int Id { get; set; }
}

解决方法一:再父类中添加一个无参数的构造函数

解决方式二:通过base在子类构造函数中调用父类有参数构造函数

StudentInfo StudentInfo = new StudentInfo("tom", "合肥", 1);
Console.ReadKey();

class PersonInfo 
{
    /// <summary>
    /// 父类中的构造函数
    /// </summary>
    /// <param name="_Name"></param>
    /// <param name="_Address"></param>
    public PersonInfo(string _Name, string _Address)
    {
        this.Name = _Name;
        this.Address = _Address;
    }

    /// <summary>
    /// 解决方式一
    /// </summary>
    //public PersonInfo()
    //{ 
        
    //}


    public string Name { get; set; }
    public string Address { get; set; }
}

class StudentInfo:PersonInfo
{
    /// <summary>
    /// 子类中的构造函数
    /// 
    /// 解决方法二,通过base调用父类有参数构造函数,通过父类初始化Name和Address属性,然后子类构造函数初始化Id属性
    /// </summary>>
    public StudentInfo(string _Name, string _Address, int _Id):base(_Name,_Address)
    { 
        this.Id = _Id;
    }

    public int Id { get; set; }
}

三、使用this调用构造函数

class PersonInfo 
{
    public PersonInfo(string _Name, string _Address)
    {
        this.Name = _Name;
        this.Address = _Address;
    }

    /// <summary>
    /// 这里可以通过this调用其他构造函数
    /// </summary>
   public PersonInfo(string name, string address, string city, int age) : this(name, address)
    {
        City = city;
        Age = age;
    }

    public string Name { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public int Age { get; set; }
}

四、访问修饰符

  • public:所有地方都可以访问
  • private:私有的,只有在本类中访问
  • internal:只有再当前程序集中可以访问,exe,dll 程序集
  • protected:当前类内部,和所有它子类的内部都可以访问
  • protected internal:同时拥有internal 和 protected的访问权限,再子类内部也行,再程序集里面也行。或的关系

        类的成员变量不写访问修饰符的情况下默认是private,类本身如果不写访问修饰符情况下默认是internal。

        直接定义再命名空间中的类型访问修饰符只能是public或者internal。·

六、访问修饰符不一致问题

        子类的访问修饰符不能大于父类的访问修饰符;

        类中的方法的参数和返回值的不能小于类的访问修饰符;

        类中的属性访问修饰符不能小于类的访问修饰符

class PersonInfo 
{
    public string Name { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public int Age { get; set; }
}

/// <summary>
/// 当StudentInfo 为public,PersonInfo为internal 编译报错
/// </summary>
public class StudentInfo:PersonInfo
{

    public int Id { get; set; }
}
class PersonInfo 
{
    public string Name { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public int Age { get; set; }
}

/// <summary>
/// 当StudentInfo 为public,PersonInfo为internal 编译报错
/// </summary>
public class StudentInfo
{

    public int Id { get; set; }

    /// <summary>
    /// 当属性的访问修饰符和类不一致时候编译器报错
    /// </summary>
    public PersonInfo Person { get; set; }

    /// <summary>
    /// 当方法参数和返回值访问修饰符和类不一致时候编译器报错
    /// </summary>
    /// <param name="personInfo"></param>
    /// <returns></returns>
    public PersonInfo Test(PersonInfo personInfo)
    {
        personInfo.Address = "111";
        return personInfo;
    }
}

 7、里氏替换原则

  我们可以使用父类类型去接受子类类型的对象。

Person person = new Student();//使用父类类型接受子类类型对象

8、子类重写从父类中的方法

        父类中通过virtual定义虚方法,子类通过override关键字进行重写

        

person.name = "张三";//继承父类的属性
person.sex = "男";//继承父类的属性
//person.studentid = "001";
person.GetName();//继承父类的方法 没有重写之前调用父类的方法;重写之后调用的就是子类中的方法
Console.ReadKey();

/// <summary>
/// 人类
/// </summary>
class Person
{
    public string name { get; set; }
    public string sex { get; set; }

    /// <summary>
    /// 加上virtual关键字,子类可以重写父类中的方法
    /// </summary>
    public virtual void GetName()
    {
        Console.WriteLine("我是父类中的方法");
    }
}

/// <summary>
/// 学生类 继承Person类
/// </summary>
class Student:Person//通过:类名 继承别的类
{
    public string studentid { get; set; }

    /// <summary>
    /// 通过override关键字进行方法重写
    /// </summary>
    public override void GetName()
    {
        //base.GetName();调用父类中的GetName方法
        Console.WriteLine("我是子类中的方法");
    }
}

九、通过继承实现多态

        多态,我的理解就是通过一句代码实现多种表现形态;举例:我这里有苹果、香蕉、橘子,这三种水果有他们各自的颜色,我想要获取出其中一种水果的颜色,普通写法代码下发如下:

/**
 * 我这里有三个类Banana、Apple、Orange,我要分别显示他们的颜色,
 * 我需要分别为他们new出对象,然后调用显示他们颜色的方法
 */
Banana banana = new Banana();
Apple apple = new Apple();
Orange orange = new Orange();
banana.MyColor();
apple.MyColor();
orange.MyColor();

Console.ReadKey();

class Banana
{
    public void MyColor() 
    {
        Console.WriteLine("我是黄色");
    }
}

class Apple 
{
    public void MyColor()
    {
        Console.WriteLine("我是红色");
    }
}

class Orange 
{
    public void MyColor()
    {
        Console.WriteLine("我是橙色");
    }
}

    以上这种写法也是可以,只不过假如以后我要增加一个水果,更换水中,调用的地方就不需要进行更改,new不同的对象即可。

Fruit fruit = new Apple();//这里只需要new不同的对象,就可以调用不同子类中实现
fruit.MyColor();//这里调用就不需要进行修改

Console.ReadKey();

class Fruit
{
    public virtual void MyColor() 
    {
        Console.WriteLine("我是水果,我不知道是什么颜色");
    }
}

class Banana: Fruit
{
    public override void MyColor() 
    {
        Console.WriteLine("我是黄色");
    }
}

class Apple : Fruit
{
    public override void MyColor()
    {
        Console.WriteLine("我是红色");
    }
}

class Orange : Fruit
{
    public override void MyColor()
    {
        Console.WriteLine("我是橙色");
    }
}

十、继承中base和this使用

        在使用父类和子类属性的时候,base和this基本没啥区别,因为它们都指向同一个对象。但是当子类重写了父类中的方法时候,子类就可以通过base和this分别调用子类重写之后的方法和父类未重写的方法。

StudentInfo StudentInfo = new StudentInfo();
StudentInfo.Test2();
Console.ReadKey();

class PersonInfo 
{
    public string Name { get; set; }

    public virtual void Test()
    {
        Console.WriteLine("我是父类!");
    }
}


class StudentInfo: PersonInfo
{

    public int Id { get; set; }

    public void Test2()
    {
        //this.Test();//调用子类中重写父类的Test方法 输出:我是子类
        base.Test();//调用父类中Test方法 输出:我是父类
    }

    public override void Test()
    {
        Console.WriteLine("我是子类");
    }
}

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值