C# 学习笔记 07:继承(Inheritance):父与子的羁绊
🧬 开篇:皮皮的「生物大爆发」
皮皮最近彻底上头了。
学会了 class 之后, 他开始疯狂造物:
- 写了一个 Slime(史莱姆),有
Hp、Attack - 写了一个 Dragon(巨龙),也有
Hp、Attack,多了 Fly
然后问题来了。
皮皮看着代码,崩溃地发现:
“等等, 我是不是一直在写同样的东西?”
每个怪物都有:
他每加一种怪, 就复制粘贴一整套。
皮皮扶额:
“我在写怪物, 还是在写复读机?”
瓜瓜叹了口气:
“你这是在无性繁殖。 该学会——继承血统了。”
第一关:找到共同祖先(Base Class)
继承的核心思想只有一句话:
提取公因式
我们要把所有怪物都有的共性,提取出来,放在一个父类 (Base Class) 里。
怪物祖先 (父类):
// 所有怪物的共同血统publicclassMonster{publicstring Name;publicint Hp;publicvoidMove() { Console.WriteLine($"{Name} 正在移动..."); }}
这个类本身不炫技, 但它定义了:
“只要是怪物, 至少得长这样。”

第二关:子承父业(Derived Class)
现在,皮皮要创造 Dragon。 他不需要再写 Name 和 Hp 了,只需要冒号 (:) 后面跟上父类的名字。
这就像是签了一份《遗产继承协议》。
巨龙 (子类):
// 冒号 : Monster 表示“Dragon 是一种 Monster”// Dragon 自动获得了 Monster 的所有公开财产!publicclassDragon : Monster{// 子类可以有自己独有的技能publicvoidFly() { Console.WriteLine($"{Name} 飞向了天空!"); }}
这个 : 的含义非常重要:
Dragon 是一种 Monster
实际效果:
Dragon myDragon = new Dragon();myDragon.Name = "巴哈姆特"; // 从父类继承myDragon.Hp = 9999; // 从父类继承myDragon.Move(); // 用的是父类的方法myDragon.Fly(); // 自己独有的能力
你只写了一份代码, 却获得了一整条进化分支。

核心概念:
- Base Class (基类/父类) :被继承的类 (
Monster)。 - Derived Class (派生类/子类) :继承者 (
Dragon)。 - "Is-A" 关系 :Dragon is a Monster (巨龙是一个怪物)。
如果一句话说不通, 这继承就不该写。
第三关:家族机密(protected)
继承不只是能力共享, 还涉及权限。
简单回顾一下:
问题来了:
有些东西, 想留给子孙, 又不想给外人看,怎么办?
答案是:protected
publicclassMonster{protectedint Treasure = 100; // 传家宝}publicclassDragon : Monster{publicvoidCheckTreasure() { Console.WriteLine($"我有 {Treasure} 金币"); }}
外人拿不到, 但子类可以。
这是继承体系里非常常用的一种设计。
第四关:推陈出新(virtual & override)——重难点
这是继承最强大的地方!
父类 Monster 有一个 Attack 方法,默认是“撞击”。
但 Dragon 觉得这太丢人了,它想改成“喷火”。
但 Zombie 觉得这也不对,它想改成“咬人”。
同一个方法名, 不同的行为。
怎么办?
这就需要重写 (Override) 。
1. 父类允许修改 (virtual):
父亲必须由衷地说:“孩子,这招剑法你可以改。”
publicclassMonster{// virtual: 虚方法,意思是“我只是个默认实现,允许被覆盖”publicvirtualvoidAttack() { Console.WriteLine("怪物进行了普通的撞击!"); }}
2. 子类进行修改 (override):
孩子说:“看我的新招式!”
publicclassDragon : Monster{// override: 重写,意思是“我要推翻父亲的实现,用我自己的”publicoverridevoidAttack() { Console.WriteLine("巨龙喷出了烈焰!🔥🔥🔥"); }}publicclassZombie : Monster{publicoverridevoidAttack() { Console.WriteLine("僵尸咬了你一口!🧟♂️"); }}
3. 见证奇迹:
Monster m1 = new Monster();m1.Attack(); // 输出:撞击Dragon d1 = new Dragon();d1.Attack(); // 输出:喷火(自动覆盖了撞击)Zombie z1 = new Zombie();z1.Attack(); // 输出:咬你(自动覆盖了撞击)
变量类型是 Monster(父类), 真正执行的却是 Dragon 和 Zombie(子类)的版本。
这一步, 我们已经摸到了多态的门把手。
本期总结
我们今天真正学到的是:
- Inheritance (
:) :共享代码,减少复制 - Virtual / Override: 父类给默认,子类自由发挥 👉 多态的起点
课后思考(非常重要)
当你写:
new Dragon();
问题来了:
构造对象时, 是先执行父类构造函数, 还是先执行子类的?
提示一句:
先有父亲, 才有儿子。
下期预告
皮皮用继承写得很爽, 但很快又发现一个问题:
“游戏里根本不存在 叫‘怪物’的具体生物。 Monster 只是一个概念。”
既然只是概念, 为什么还能被 new 出来?
下一期,我们解决这个问题:
👉 抽象类(Abstract) & 接口(Interface)
不能被实例化的父类, 才是真正干净的设计。