CodeGym /课程 /C# SELF /继承的概念

继承的概念

C# SELF
第 20 级, 课程 0
可用

1. 入门

编程里的继承其实跟现实生活中的继承很像。比如,你可能从爸妈那儿继承了眼睛的颜色、鼻子的形状,甚至画画的天赋。这些特征你是“默认”就有的,不用自己造。但你也可以发展出自己独特的东西,是爸妈没有的。

在编程里也是类似的套路:

  • 有一个类(我们叫它基类或者父类,有时候也叫超类)定义了所有“子孙”都共有的特性(属性)和行为(方法)。
  • 另一个类(叫派生类或者子类,有时也叫子类)继承了父类的所有这些共性。它会自动获得所有public和protected的属性和方法,不用再声明一遍。
  • 派生类还可以加上自己独有的属性和方法,是父类没有的。
  • 有时候,派生类甚至可以改写继承来的方法的行为(这个我们后面讲,这叫多态)。

继承的核心思想就是“是某种东西”(is-a relationship)。比如你写一个有法师、战士和弓箭手的游戏:

  • 战士是角色。
  • 法师是角色。
  • 弓箭手是角色。

如果战士是角色,那他就得有角色该有的所有东西,再加上战士独有的特性。

2. 继承的语法

来,咱们看个例子,顺便写点代码。

语法基础


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

    public void Move()
    {
        Console.WriteLine($"{Name} 在移动。");
    }
}

// 子类
public class Dog : Animal
{
    public void Bark()
    {
        Console.WriteLine($"{Name} 在叫:汪!");
    }
}

注意Dog类名后面的冒号。这里就是在说:Dog继承了Animal的所有东西。

所有Animal里的public和protected成员,Dog都有!

继承的用法

来试试在控制台应用里用这些类:


var dog = new Dog();
dog.Name = "小花"; // Name属性是从Animal继承来的
dog.Move();         // Move方法也是Animal的
dog.Bark();         // Dog自己的方法

// 输出:
// 小花 在移动。
// 小花 在叫:汪!

你还可以造只猫,让“动物园”更丰富:

public class Cat : Animal
{
    public void Meow()
    {
        Console.WriteLine($"{Name} 在喵:喵!");
    }
}

var cat = new Cat();
cat.Name = "小咪";
cat.Move();
cat.Meow();

3. 继承怎么帮你省事

当你有好几个类似的对象时,完全没必要一遍遍复制代码。继承就像“母版”:你只写一次逻辑,所有子类都能用。

可视化:继承树


.   Animal
     /    \
  Dog    Cat
类的继承结构图
类 属性 Name 方法 Move 自有方法
Animal + + -
Dog + + Bark()
Cat + + Meow()

再举个例子——扩展应用

假如你要做一个管理不同类型人的系统。回忆下以前的写法:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

// 现在加个员工
public class Employee
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Position { get; set; }
}

这样很麻烦!名字信息重复了。用继承就对了:


public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class Employee : Person
{
    public string Position { get; set; }
}

public class Student : Person
{
    public int Grade { get; set; }
}
用继承消除代码重复

现在Employee和Student都已经有FirstName和LastName了,不用再写一遍。你可以很容易地扩展系统,支持更多角色。

这就是继承的魔力:我们把共性写在基类里,然后在子类里“扩展”功能,加上专属细节。

4. 继承的优点

代码复用(Code Reusability): 这是最明显的好处。你不用在不同地方写同样的代码。写一次,用N次。你的代码更干净、更精炼(程序员圈子里常说Don't Repeat Yourself——DRY,“别重复自己”)。

维护更简单(Easier Maintenance): 如果你要改移动的逻辑,只要在基类Animal里改一次就行。所有子类自动跟着变。想想大项目里能省多少时间!

构建层级结构(Creating Hierarchies): 继承让你能模拟现实世界的“是某种东西”关系,结构清晰,逻辑易懂。战士是角色,法师是角色。这样代码更有条理,也更容易理解。

多态的基础: 虽然我们还没详细讲多态,但继承就是它的基石。多态让你能用基类的接口操作各种子类对象。比如你可以有一个Animal的列表(不管是Dog、Cat还是别的动物),都能直接调用Move方法,不用管具体是哪种动物。这功能超强,我们后面还会细讲!

5. 继承的细节和注意点

C#只支持单继承: 跟有些语言(比如C++)不一样,C#只支持单继承。也就是说,一个类只能有一个基类。你不能同时继承Animal和比如Vehicle(假如有这个类)。

所有类默认都继承自object: 有个有趣的点!如果你没写基类,系统会自动让你的类继承自System.Object。这是.NET里最基础的类,提供了一些核心方法,比如ToString()、Equals()、GetHashCode()。所以你重写ToString()时,其实是在重写从object继承来的方法!

构造函数不会继承: 子类不会继承父类的构造函数。你得自己在子类里写构造函数。如果父类有带参数的构造函数,你必须在子类构造函数里用base关键字调用父类的构造函数。

私有成员不能直接访问: private成员在子类里不能直接访问。它们虽然在对象里存在,但你不能在子类代码里用名字访问。如果你想让子类能访问,但外部不能,就用protected修饰符。

6. 层级结构的可视化

为了更好地理解继承关系,大家常用图表。最常见的就是UML(统一建模语言)类图。比如动物的例子,图大概是这样:

classDiagram
    class Animal {
        + string Name
        + Move()
    }

    class Dog {
        + Bark()
    }

    class Cat {
        + Meow()
    }

    Animal <|-- Dog : inherits
    Animal <|-- Cat : inherits
继承例子的UML类图

在这张图里,空心三角箭头(从Dog指向Animal,从Cat指向Animal)表示继承关系:“是某种东西”(is-a relationship)。

7. 继承的实际应用

继承可不是书本上的概念,它是现代编程的基石之一,在真实项目里用得超多:

做图形界面(GUI): 在WPF、WinForms、MAUI(.NET桌面应用框架)里,几乎所有控件(按钮、文本框、窗口)都继承自Control或UIElement。这样它们都有通用属性,比如大小、位置、可见性,还有通用方法,比如事件处理。
比如,Button是Control,TextBox是Control。

游戏引擎: 继承特别适合做游戏对象的层级:GameObject → Character → Player/Enemy,或者Vehicle → Car/Motorcycle。

数据库开发(ORM): 在Entity Framework Core这种框架里,你经常会给所有实体定义一个基类,比如BaseEntity,里面有Id(数据库主键)或CreatedAt(创建时间)等属性。你所有具体的实体(比如User、Product、Order)都继承自BaseEntity,自动拥有这些属性。

测试: 继承在测试框架(比如xUnit、NUnit)里也很常见,你可以写基础测试类,封装通用的初始化和清理逻辑,具体测试类继承它们就行。

类库和框架: .NET标准库本身就大量用继承。比如很多集合和类型都继承自通用基类,或者实现通用接口(这个我们以后会讲)。

C#和.NET面试里,关于继承、它的原则(DRY、is-a),以及它和其他概念(比如组合、接口)的区别,都是最基础、最常见的题。你不仅要能讲清楚,还要能举出实际代码或生活里的例子,这很加分。

所以你看,继承不是语言的“花活”,而是结构化代码、减少重复、构建逻辑体系的利器。它是写出可扩展、易维护代码的关键。

2
任务
C# SELF, 第 20 级, 课程 0
已锁定
继承与基类
继承与基类
2
任务
C# SELF, 第 20 级, 课程 0
已锁定
功能扩展
功能扩展
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION