深入理解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技术站