C# - 继承:初学者的全面指南

你好,有抱负的程序员们!今天,我们将踏上一段激动人心的旅程,探索C#继承的世界。别担心,如果你是编程新手——我会成为你的友好向导,我们将一起一步步地探索这个概念。在本教程结束时,你将牢固掌握继承的概念,以及它如何使你的代码更高效、更有组织。

C# - Inheritance

什么是继承?

在我们深入细节之前,让我们从一个简单的类比开始。想象你在创建一个家谱树。家谱树中的每个人都会从他们的父母那里继承某些特质,对吧?在编程中,继承的工作方式与此类似!

在C#中,继承是一种机制,允许一个新类基于一个已存在的类。新类继承现有类的属性和方法,就像你可能继承了你父母的眼睛颜色或身高一样。

基类和派生类

在继承的世界中,我们有两个主要角色:

  1. 基类(也称为父类或超类):这是包含公共属性和方法的原始类。
  2. 派生类(也称为子类或子类):这是从基类继承的新类。

让我们来看一个简单的例子:

// 基类
public class Animal
{
public string Name { get; set; }
public int Age { get; set; }

public void Eat()
{
Console.WriteLine($"{Name} is eating.");
}
}

// 派生类
public class Dog : Animal
{
public void Bark()
{
Console.WriteLine($"{Name} says Woof!");
}
}

在这个例子中,Animal是我们的基类,Dog是我们的派生类。Dog类声明中的: Animal部分告诉我们,DogAnimal继承。

现在,让我们看看如何使用这些类:

Dog myDog = new Dog();
myDog.Name = "Buddy";
myDog.Age = 3;

myDog.Eat();  // 从Animal继承
myDog.Bark(); // 在Dog中定义

当我们运行这段代码时,我们将看到:

Buddy is eating.
Buddy says Woof!

这难道不酷吗?我们的Dog类可以访问Animal类中的NameAge属性,以及Eat()方法,而无需我们重新编写所有代码!

初始化基类

现在,你可能会有疑问:“当我创建一个派生类对象时,如果我想要为基类设置一些初始值怎么办?”这是个好问题!这就是构造函数发挥作用的地方。

让我们修改我们的例子:

public class Animal
{
public string Name { get; set; }
public int Age { get; set; }

public Animal(string name, int age)
{
Name = name;
Age = age;
}

public void Eat()
{
Console.WriteLine($"{Name} is eating.");
}
}

public class Dog : Animal
{
public Dog(string name, int age) : base(name, age)
{
// 如果需要,为Dog进行额外的初始化
}

public void Bark()
{
Console.WriteLine($"{Name} says Woof!");
}
}

在这个更新的版本中,我们为Animal类添加了一个构造函数。Dog类构造函数使用: base(name, age)语法来调用基类构造函数并传递nameage参数。

现在我们可以这样创建一个Dog对象:

Dog myDog = new Dog("Buddy", 3);
myDog.Eat();
myDog.Bark();

这将产生与之前相同的输出,但是现在我们在创建Dog对象时初始化了NameAge属性。

C#中的多重继承

现在,来个转折:与其他一些编程语言不同,C#不支持类的多重继承。这意味着一个类不能直接从多个基类继承。

但是别担心!C#有一个使用接口的巧妙替代方法。接口就像一个合同,指定了一个类应该做什么,而不是定义它应该如何做。

让我们看一个例子:

public interface ISwimmable
{
void Swim();
}

public interface IFlyable
{
void Fly();
}

public class Bird : Animal, IFlyable
{
public Bird(string name, int age) : base(name, age) { }

public void Fly()
{
Console.WriteLine($"{Name} is flying.");
}
}

public class Fish : Animal, ISwimmable
{
public Fish(string name, int age) : base(name, age) { }

public void Swim()
{
Console.WriteLine($"{Name} is swimming.");
}
}

public class Duck : Animal, ISwimmable, IFlyable
{
public Duck(string name, int age) : base(name, age) { }

public void Swim()
{
Console.WriteLine($"{Name} is swimming.");
}

public void Fly()
{
Console.WriteLine($"{Name} is flying.");
}
}

在这个例子中,我们创建了两个接口:ISwimmableIFlyable。我们的Bird类从Animal继承并实现IFlyableFish类从Animal继承并实现ISwimmable。看看我们的Duck类——它从Animal继承并实现了ISwimmableIFlyable

让我们使用这些类:

Bird myBird = new Bird("Tweety", 2);
myBird.Fly();

Fish myFish = new Fish("Nemo", 1);
myFish.Swim();

Duck myDuck = new Duck("Donald", 5);
myDuck.Swim();
myDuck.Fly();

这将输出:

Tweety is flying.
Nemo is swimming.
Donald is swimming.
Donald is flying.

这难道不令人惊叹吗?我们的Duck既会游泳又会飞翔,尽管C#不支持类的多重继承!

方法表

以下是我们示例中使用的方法的表格总结:

类/接口 方法 描述
Animal Eat() 打印一个消息,表明动物正在吃东西
Dog Bark() 打印一个消息,表明狗正在吠叫
ISwimmable Swim() 定义一个游泳的方法
IFlyable Fly() 定义一个飞翔的方法
Bird Fly() 实现Fly方法
Fish Swim() 实现Swim方法
Duck Swim(), Fly() 实现Swim和Fly方法

就是这样!我们已经涵盖了C#继承的基础知识,从简单的基类和派生类到使用接口的更复杂场景。记住,继承是关于代码重用和创建类之间的逻辑关系。它是一个强大的工具,可以使你的代码更高效、更易于维护。

在你继续编程之旅时,你会发现许多使用继承来解决复杂问题的方法。继续练习,不要害怕尝试这些概念。快乐编码!

Credits: Image by storyset