深入理解C#之继承

深入理解C#之继承

继承是面向对象编程中非常重要的一种机制,它可以使得我们代码重用性更高,更加简洁。在C#中,继承可以通过类之间的关系来实现(类之间的关系有继承、实现、组合等)。在本篇文章中,我们将学习C#中的继承机制,重点包括如下内容:

  • 继承的语法和基本概念
  • 虚方法和抽象类
  • 接口继承
  • 隐藏和重写方法
  • 继承链

继承的语法和基本概念

在C#中,使用:符号表示一个类继承自另一个类。例如,我们可以这样定义一个汽车类继承自交通工具类:

class Vehicle {
    // 交通工具类
}
class Car : Vehicle {
    // 汽车类继承自交通工具类
}

汽车类继承自交通工具类,那么汽车类就可以自动获得交通工具类中的所有属性和方法,无需重新定义。我们称交通工具类为父类或基类,汽车类为子类或派生类。

虚方法和抽象类

在父类中定义的方法,子类可以继承并使用。然而,在某些情况下,子类需要重写父类中的方法,例如:子类需要根据自己的特殊需求来重新实现某个方法。这就需要我们使用virtual关键字定义虚方法,例如:

class Vehicle {
    public virtual void Go() {
        Console.WriteLine("Vehicle is going.");
    }
}
class Car : Vehicle {
    public override void Go() {
        Console.WriteLine("Car is running.");
    }
}

在上面的代码中,我们定义了Vehicle类中的Go方法,使用了virtual关键字,表示这是一个虚方法,可以被子类重写。在Car类中,我们使用了override关键字来重写Go方法,并实现了自己的功能。

抽象类是父类中的一种特殊形式,它不能被直接实例化,只能被继承。抽象类中可以包含抽象方法,抽象方法必须被子类重写,否则子类也必须是抽象类。例如:

abstract class Vehicle {
    public abstract void Go();
}
class Car : Vehicle {
    public override void Go() {
        Console.WriteLine("Car is running.");
    }
}

接口继承

除了类继承,C#还提供了接口继承。一个接口定义了一组属性、方法和事件,但不包含实现。一个类可以实现一个或多个接口,以声明自己支持这些接口所定义的功能。例如:

interface IVehicle {
    void Go();
}
class Car : IVehicle {
    public void Go() {
        Console.WriteLine("Car is running.");
    }
}

上面的代码中,我们定义了一个IVehicle接口,它有一个Go方法。Car类实现了IVehicle接口,并实现了Go方法。

隐藏和重写方法

在C#中,派生类可以定义与基类同名的方法,这就涉及到隐藏和重写的概念。如果在派生类中定义了一个方法与基类中同名的方法,那么该方法就会隐藏基类中的方法。如果要调用基类中的方法,可以使用base关键字来指定。例如:

class Vehicle {
    public virtual void Go() {
        Console.WriteLine("Vehicle is going.");
    }
}
class Car : Vehicle {
    public new void Go() {
        Console.WriteLine("Car is running.");
    }
    public void GoBase() {
        // 调用基类的Go方法
        base.Go();
    }
}

在上面的代码中,我们定义了Car类的Go方法,它与基类中的Go方法同名。使用new关键字表示我们要隐藏基类中的方法。在Car类中,我们还定义了一个GoBase方法来调用基类的Go方法。

如果希望在派生类中重写基类的方法,需要使用override关键字。例如:

class Vehicle {
    public virtual void Go() {
        Console.WriteLine("Vehicle is going.");
    }
}
class Car : Vehicle {
    public override void Go() {
        Console.WriteLine("Car is running.");
        // 调用基类的Go方法
        base.Go();
    }
}

在上面的代码中,我们使用override关键字来重写基类的Go方法,并在子类中添加自己的实现。

继承链

在C#中,继承可以是多层嵌套的。例如:

class Vehicle {
    public virtual void Go() {
        Console.WriteLine("Vehicle is going.");
    }
}
class Car : Vehicle {
    public override void Go() {
        Console.WriteLine("Car is running.");
        base.Go();
    }
}
class Mustang : Car {
    public new void Go() {
        Console.WriteLine("Mustang is running.");
        base.Go();
    }
}

在上面的代码中,Mustang类继承自Car类,而Car类又继承自Vehicle类。因此,Mustang类不仅可以使用自己的方法,还可以使用父类和祖先类中的方法。必要时,还可以使用base关键字来访问特定层次的父类方法。

示例1:基类与派生类的方法重载

下面的代码演示了在基类和派生类中实现方法重载的方式:

using System;

namespace Demo1
{
    class Program
    {
        static void Main(string[] args)
        {
            // 创建一个Animal对象
            Animal animal1 = new Animal();
            // 调用Animal中的eat方法
            animal1.eat("grass");

            Console.WriteLine();

            // 创建一个Dog对象
            Dog dog1 = new Dog();
            // 调用Animal中的eat方法
            dog1.eat("bone");
            // 调用Dog中的eat方法
            dog1.eat("bone", 2);

            Console.ReadKey();
        }
    }

    class Animal
    {
        public void eat(string food)
        {
            Console.WriteLine("Animal is eating " + food);
        }

        public virtual void eat(string food, int count)
        {
            for (int i = 0; i < count; i++)
            {
                eat(food);
            }
        }
    }

    class Dog : Animal
    {
        public void eat(string food)
        {
            Console.WriteLine("Dog is eating " + food);
        }
    }

}

输出:

Animal is eating grass

Animal is eating bone
Dog is eating bone

在上面的代码中,我们定义了一个Animal类和一个Dog类。在Animal类中,我们定义了一个名为eat的方法,它接受一个参数food,输出一个信息。在Dog类中,我们也定义了一个名为eat的方法,但它与Animal类中的eat方法参数不同。我们还为Animal类和Dog类中的eat方法都添加了一个重载版本,其中Animal类中的版本是虚方法。

我们通过创建Animal和Dog对象来演示这些方法的使用。在Dog对象上调用eat方法时,如果传入一个参数,将会调用Dog类中的eat方法;如果传入两个参数,将会调用Animal类的虚方法。

示例2:多级继承示例

下面的代码演示了多级继承的示例,其中将定义三个类:

using System;

namespace Demo2
{
    class Program
    {
        static void Main(string[] args)
        {
            Employee emp1 = new Employee("Jack", "Xu", 2000);
            Manager mgr1 = new Manager("Bob", "Lee", 5000, "IT");
            Director dir1 = new Director("Amy", "Zhang", 10000, "Higher Education");

            emp1.print();
            mgr1.print();
            dir1.print();

            Console.ReadKey();
        }
    }

    class Employee
    {
        private string firstName;
        private string lastName;
        private decimal salary;

        public Employee(string fName, string lName, decimal sal)
        {
            firstName = fName;
            lastName = lName;
            salary = sal;
        }

        public void print()
        {
            Console.WriteLine("Employee Information: " + firstName + " " + lastName + ", Salary: " + salary);
        }
    }

    class Manager : Employee
    {
        private string department;

        public Manager(string fName, string lName, decimal sal, string dept) :
            base(fName, lName, sal)
        {
            department = dept;
        }

        public new void print()
        {
            Console.WriteLine("Manager Information: " + firstName + " " + lastName + ", Salary: " + salary + ", Department: " + department);
        }
    }

    class Director : Manager
    {
        private string institution;

        public Director(string fName, string lName, decimal sal, string dept) :
            base(fName, lName, sal, dept)
        {
            institution = "Our Institution";
        }

        public override void print()
        {
            Console.WriteLine("Director Information: " + firstName + " " + lastName + ", Salary: " + salary + ", Department: " + department + ", Institution: " + institution);
        }
    }
}

输出:

Employee Information: Jack Xu, Salary: 2000
Manager Information: Jack Xu, Salary: 5000, Department: IT
Director Information: Amy Zhang, Salary: 10000, Department: Higher Education, Institution: Our Institution

在上面的代码中,我们定义了三个类:Employee、Manager和Director。每个类都继承自前一个类,并添加了自己的成员。在Main方法中,我们创建了一个Employee、一个Manager和一个Director对象,分别调用它们的print方法。

我们可以看到,Employee类和Manager类中都定义了print方法,但Manager类中的版本是新方法。Director类重写了Manager类中的print方法,使用了override关键字。在Main方法中,我们创建了三个对象,并调用它们的print方法。在Director对象上调用print方法时,它将执行Director类中的版本,而不是Manager类中的版本。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:深入理解C#之继承 - Python技术站

(0)
上一篇 2023年5月15日
下一篇 2023年5月15日

相关文章

  • 浅谈C#中的string驻留池

    下面是详细讲解C#中的string驻留池的完整攻略: 什么是字符串驻留池 字符串是C#语言中最常用的数据类型之一。为了避免构造新的字符串对象导致大量的内存和GC(垃圾回收)压力,C#中引入了字符串驻留池(string intern pool)的概念,用于缓存小字符串对象。驻留池的原理是:当构造了一个字符串对象,并把它赋给一个变量时,.NET运行时会首先检查驻…

    C# 2023年5月31日
    00
  • 如何使用Swagger上传文件

    Swagger是一种流行的API文档工具,它可以帮助开发人员快速创建和测试API。在Swagger中,可以使用Swagger UI来测试API,其中包括上传文件的功能。下面是如何使用Swagger上传文件的完整攻略: 步骤一:安装Swagger 首先,需要安装Swagger。可以使用以下命令在.NET Core应用程序中安装Swagger: dotnet a…

    C# 2023年5月17日
    00
  • C#中的属性解析(get、set、value)

    当我们定义一个类时,通常需要为类的成员添加一些限制以确保数据的正确性和安全性。属性解析(get、set、value)就是一种常用的实现方式之一。 属性解析 属性解析指的是在属性中添加代码,以便在读取和写入属性时执行特定的操作。具体而言,需要为属性添加get访问器和/或set访问器。 当获取属性时,代码将进入get访问器,并执行其中的代码。同样,当设置属性值时…

    C# 2023年5月31日
    00
  • C# 开发step步骤条控件详解

    下面是关于C#开发步骤条控件的详细攻略。 1. 概述 步骤条控件可以帮助用户更加清晰地了解当前操作处于哪一步,以及距离完成还有多少步。在C#开发中,我们可以使用自定义控件来实现步骤条的功能。 本篇攻略将会介绍如何使用C#开发步骤条控件,包括控件设计、属性设置、事件处理等。 2. 控件设计 2.1 创建新控件 在Visual Studio中,我们可以通过以下步…

    C# 2023年6月3日
    00
  • c#如何用好垃圾回收机制GC

    下面是讲解“C#如何用好垃圾回收机制GC”的完整攻略: 1. 垃圾回收机制介绍 C#语言中的垃圾回收机制是一种自动内存管理方式,通过动态分配内存并在不再需要时进行自动回收来避免内存泄漏。垃圾回收器通常会在程序运行时自动扫描活动对象,找到不再被使用的对象并将其标记为垃圾,然后清理这些垃圾对象所占用的内存空间。 垃圾回收机制是由.Net Framework库提供…

    C# 2023年5月15日
    00
  • C# 实现简单打印的实例代码

    C# 实现简单打印的实例代码 简介 在 C# 中,我们可以通过 System.Drawing.Printing 命名空间提供的 PrintDocument 类来实现简单的文本打印。 步骤 1. 引入命名空间 使用 PrintDocument 类需要引入 System.Drawing.Printing 命名空间。 using System.Drawing.Pr…

    C# 2023年5月31日
    00
  • 免费开源百度编辑器(UEditor)使用方法

    下面我为您详细讲解“免费开源百度编辑器(UEditor)使用方法”的完整攻略。UEditor是一款基于JavaScript的所见即所得富文本编辑器,具有简单易用、兼容性好、功能强大等优点。本攻略主要分为以下几步: 1. 下载UEditor 首先,我们需要到UEditor的官方网站(http://ueditor.baidu.com/website/downlo…

    C# 2023年6月6日
    00
  • 详解C#中使用对象或集合的初始值设定项初始化的操作

    使用C#中的对象或集合初始化器,可以方便地对对象或集合进行初始化操作。对象初始化器用于初始化对象的字段和属性,而集合初始化器用于初始化集合中的元素。 以下是使用对象初始化器初始化对象的示例: public class Person { public string Name { get; set; } public int Age { get; set; } …

    C# 2023年5月31日
    00
合作推广
合作推广
分享本页
返回顶部