跳到主要内容

C# 继承

提示
  1. C#中继承的基本概念:在C#中,继承是面向对象编程的核心特性,允许从现有类(基类)创建新类(派生类),继承基类的字段和方法,增强代码的可重用性。
  2. 继承的实现方式:使用 : 符号实现继承,派生类继承基类的成员,支持方法重写和 protected 成员的访问。存在单继承、多级继承、分层继承,但C#不支持多重继承。
  3. 继承的重要性与应用:继承提高代码重用性和可维护性。通过示例说明继承如何在不同形状(如正方形、矩形)的计算中实现代码复用和扩展。

在 C# 中,继承允许我们从现有类创建一个新类。它是面向对象编程(OOP)的一个关键特性。

作为新类创建基础的类被称为基类(父类或超类)。而新类被称为派生类(子类或子类)。

派生类继承了基类的字段和方法。这有助于 C# 中代码的可重用性。

如何在 C# 中实现继承?

在 C# 中,我们使用 : 符号来执行继承。例如,

class Animal {
// 字段和方法
}

// Dog 继承自 Animal
class Dog : Animal {
// Animal 的字段和方法
// Dog 的字段和方法
}

这里,我们将派生类 Dog 从基类 Animal 继承。Dog 类现在可以访问 Animal 类的字段和方法。C# 继承

示例:C# 继承

using System;

namespace Inheritance {

// 基类
class Animal {

public string name;

public void display() {
Console.WriteLine("我是一只动物");
}

}

// Animal 的派生类
class Dog : Animal {

public void getName() {
Console.WriteLine("我的名字是 " + name);
}
}

class Program {

static void Main(string[] args) {

// 派生类的对象
Dog labrador = new Dog();

// 访问基类的字段和方法
labrador.name = "Rohu";
labrador.display();

// 访问自己类的方法
labrador.getName();

Console.ReadLine();
}

}
}

输出

我是一只动物
我的名字是 Rohu

在上述示例中,我们从超类 Animal 派生了一个子类 Dog。注意以下语句,

labrador.name = "Rohu";

labrador.getName();

这里,我们使用 labrador(Dog 的对象)来访问 Animal 类的 namedisplay()。这是因为派生类继承了基类的所有字段和方法。

此外,我们还在 Dog 类的方法中访问了 name 字段。

is-a 关系

在 C# 中,继承是一种 is-a 关系。我们只在两个类之间存在 is-a 关系时使用继承。例如,

  • Dog(狗) 是一种 Animal(动物)
  • Apple(苹果) 是一种 Fruit(水果)
  • Car(汽车) 是一种 Vehicle(交通工具)

我们可以从 Animal 类派生 Dog。类似地,Apple 可以从 Fruit 类派生,Car 可以从 Vehicle 类派生。

C# 继承中的 protected 成员

当我们将一个字段或方法声明为 protected 时,它只能从同一个类及其派生类中访问。

示例:继承中的 protected 成员

using System;

namespace Inheritance {

// 基类
class Animal {
protected void eat() {
Console.WriteLine("我会吃");
}
}

// Animal 的派生类
class Dog : Animal {
static void Main(string[] args) {

Dog labrador = new Dog();

// 访问基类的 protected 方法
labrador.eat();

Console.ReadLine();
}
}
}

输出

我会吃

在上述示例中,我们创建了一个名为 Animal 的类。该类包含了一个受保护的方法 eat()

我们从 Animal 类派生出了 Dog 类。注意这个语句,

labrador.eat();

由于 protected 方法可以在派生类中访问,我们可以在 Dog 类中访问 eat() 方法。

继承的类型

有以下几种类型的继承:

1. 单继承

在单继承中,一个派生类从一个基类继承。

C# 单继承

2. 多级继承

在多级继承中,一个派生类从一个基类继承,然后同一个派生类又作为基类为另一个类提供继承。

C# 多级继承

3. 分层继承

在分层继承中,多个派生类从一个基类继承。

C# 分层继承

4. 多重继承

在多重继承中,一个派生类从多个基类继承。C# 不支持多重继承。 但是,我们可以通过接口实现多重继承。

多重继承

5. 混合继承

混合继承是两种或更多类型继承的组合。多级和分层继承的组合就是混合继承的一个例子。

C# 混合继承

C# 继承中的方法重写

如果基类和派生类中都存在相同的方法,派生类中的方法将重写基类中的方法。这在 C# 中称为方法重写。例如,

using System;

namespace Inheritance {

// 基类
class Animal {
public virtual void eat() {

Console.WriteLine("我吃食物");
}
}

// Animal 的派生类
class Dog : Animal {

// 重写 Animal 的方法
public override void eat() {

Console.WriteLine("我吃狗粮");
}
}
class Program {

static void Main(string[] args) {
// 派生类的对象
Dog labrador = new Dog();

// 访问重写的方法
labrador.eat();
}
}
}

输出

我吃狗粮

在上述示例中,eat() 方法在基类和派生类中都存在。

当我们使用 Dog 对象 labrador 调用 eat() 时,

labrador.eat();

调用的是 Dog 内部的方法。这是因为 Dog 中的方法重写了 Animal 中的同名方法。

注意,我们分别在基类和派生类的方法中使用了 virtualoverride。这里,

  • virtual - 允许方法被派生类重写
  • override - 表明该方法重写了基类的方法

C# 继承中的 base 关键字

在前面的示例中,我们看到派生类中的方法重写了基类中的方法。

但是,如果我们想同时调用基类的方法怎么办?

在这种情况下,我们使用 base 关键字从派生类中调用基类的方法。

示例:C# 继承中的 base 关键字

using System;

namespace Inheritance {

// 基类
class Animal {
public virtual void eat() {

Console.WriteLine("动物吃食物。");
}
}

// Animal 的派生


class Dog : Animal {

// 重写 Animal 的方法
public override void eat() {

// 调用 Animal 类中的方法
base.eat();

Console.WriteLine("狗吃狗粮。");
}
}
class Program {

static void Main(string[] args) {

Dog labrador = new Dog();
labrador.eat();
}
}
}

输出

动物吃食物。
狗吃狗粮。

在上述示例中,eat() 方法存在于基类 Animal 和派生类 Dog 中。注意以下语句,

base.eat();

这里,我们使用了 base 关键字从 Dog 类访问 Animal 类的方法。

C# 中继承的重要性

为了理解继承的重要性,让我们考虑一个情况。

假设我们正在处理正多边形,如正方形、矩形等。我们需要根据输入计算这些多边形的周长。

1. 由于计算周长的公式对所有正多边形都是通用的,我们可以创建一个 RegularPolygon 类和一个 calculatePerimeter() 方法来计算周长。

class RegularPolygon {

calculatePerimeter() {
// 计算周长的代码
}
}

2. 并从 RegularPolygon 类继承 SquareRectangle 类。这些类中的每一个都会有属性来存储边长和边数,因为它们对于所有多边形都是不同的。

class Square : RegularPolygon {

int length = 0;
int sides = 0;
}

我们将 lengthsides 的值传递给 calculateperimeter() 来计算周长。

这就是继承如何使我们的代码可重用和更直观。

示例:继承的重要性

using System;

namespace Inheritance {

class RegularPolygon {

public void calculatePerimeter(int length, int sides) {

int result = length * sides;
Console.WriteLine("周长: " + result);
}
}

class Square : RegularPolygon {

public int length = 200;
public int sides = 4;
public void calculateArea() {

int area = length * length;
Console.WriteLine("正方形的面积: " + area);
}
}

class Rectangle : RegularPolygon {

public int length = 100;
public int breadth = 200;
public int sides = 4;

public void calculateArea() {

int area = length * breadth;
Console.WriteLine("矩形的面积: " + area);
}
}

class Program {

static void Main(string[] args) {

Square s1 = new Square();
s1.calculateArea();
s1.calculatePerimeter(s1.length, s1.sides);


Rectangle t1 = new Rectangle();
t1.calculateArea();
t1.calculatePerimeter(t1.length, t1.sides);

}
}
}

输出

正方形的面积: 40000
周长: 800
矩形的面积: 20000
周长: 400

在上述示例中,我们创建了一个 RegularPolygon 类,它有一个计算正多边形周长的方法。

这里,SquareRectangle 继承自 RegularPolygon

计算周长的公式对所有形状都是通用的,因此我们重用了基类的 calculatePerimeter() 方法。

由于计算不同形状的面积的公式不同,我们在派生类中创建了一个单独的方法来计算面积。