继承

经常会需要扩展现有的类型来添加方法或数据。比如我们首先有一个Student类来存储学生的姓名、年龄等信息,现在需要建立一个类BoyStudent来存储男同学的兴趣爱好。因为每个男同学都是学生,因此Students类中的所有内容都应该被包含在BoyStudent类;另一方面,BoyStudent类中还包含Student类中不包含的内容,如兴趣的种类。在这种情况下,BoyStudent类就可以在Student类的基础上建立,即在Student类的基础上添加新的内容。我们可以称BoyStudent类继承自Student类,其中Student类称为基类,BoyStudent称为派生类。

来看两段代码。

//基类 
public class Student
{
    public string Name{get;set}
    private int Age{get;set}
    public virtual string Teacher{get;set}//允许重写的属性
}
// 派生类
public class BoyStudent : Student
{
    public string Hobby{get;set}
    public string TeacherName;
    public override string Teacher
    {
        get
        {
            return $"Dear {TeacherName}";
        }
        set 
        {
            TeacherName = value;
        }
    }
}
// 调用
public class Program
{
    public static void Main()
    {
        BoyStudent boyStudentTom = new BoyStiudent();
        boyStudent1.Name = "Tom";
        
        Student studentTom = boyStudentTom;// 类型转换
    }
}
  • 继承的标识符是":","A:B"表示类A继承自类B。
  • C#的类是单继承的,这意味着":"后面只能写一个类。
  • 如调用中的函数所示,虽然没有在BoyStudent类中定义Name属性,但是在它的基类Student中有public的Name属性,因此可以直接进行访问,或者说,每个派生类继承除构造函数和析构器之外的所有基类成员。但是继承不意味着可以访问,Student类中的Age属性,被限定为private,它不可以在派生类中进行访问。除了public和private这两个极端的修饰,还有一个折中的修饰符protected,它意味着改成员只有基类及其派生类可以访问。
  • 派生类可以转换成基类,调用中转换的代码是隐式转换,也可以使用显式转换。但是注意,派生类向基类转换是可以的,但是基类向派生类转换不可以。因为派生类一定属于基类,但是基类不一定属于派生类。
  • 如果基类中的某些成员不太满足派生类的要求,可以在派生类中重写。但是C#只支持重写实例方法和属性,不支持字段和任何静态成员的重写。此外,必须在基类中将每个允许重写的成员都用virtual修饰符修饰,在派生类重写时,要加上override修饰符。
  • 如果不希望被重写,可以对成员加上sealed修饰符修饰。
  • 所有的类直接或间接从object派生。
  • 有一种类是抽象类,其抽象成员定义了从抽象实体派生的对象应包含什么,但这种成员不包含实现。抽象类的大多数功能通常都没有实现。一个类要从抽象类成功地派生,必须为抽象基类中的抽象方法提供具体的实现。抽象类需要在类前加abstract修饰符修饰。

接口

接口有点像协议,在其中定义实现的某些功能的方法名称和这些方法需要的参数类型。这样的话,该接口的所有派生类的实例,在调用该方法时就会有统一的格式。

// 定义接口
 interface IfileWrite
 {
     void FileWrite(string address,string fileName);
 }
  • 接口用interface关键字声明,按照约定,接口的名称最好加一个I前缀。
  • 接口不包含实现和数据,在接口中不能出现字段,但是可以包含属性,属性不能引用支持字段,接口中也不能拥有静态成员。
  • C#不允许为接口成员使用访问修饰符,所有成员自动公共。
  • 接口永远不能实例化,接口不含有构造函数和终结器。
// 接口派生类
 class Example:IfileWrite
 {
     public void FileWrite(string address,string fileName)
     {
         ...//具体实现
     }
 }
  • 声明类来实现接口类似于从基类派生——要实现的接口和基类名称以逗号分隔(基类在前,接口顺序任意)。类可实现多个接口,但只能从一个基类直接派生。
  • 实现接口时,接口的所有成员都必须实现。实现方式有显式实现和隐式实现两种,上文的例子是隐式实现。
  • 一个接口可以从另一个或多个接口派生,派生的接口将继承“基接口”的所有成员。

盛夏的猫宁
23 声望2 粉丝