本篇 核心知识点 :面向对象三大特性之继承、动态多态(虚方法 virtual/override)、静态多态(函数重载)、new 隐藏函数、base 关键字、抽象类 abstract、抽象方法、类构造 / 析构执行顺序、is/as 类型转换、实战动物类案例、游戏植物实战拓展
一、继承(Inheritance)
1. 核心概念
继承是面向对象三大特性(封装、继承、多态)之一,用于提取多个类的公共属性与方法,抽取为父类(基类 / Base Class),子类(派生 / Derived Class)直接复用,仅编写独有逻辑,减少重复代码,实现代码复用。
类之间语义为「is-a」:如向日葵是植物、狗是动物。
2. C# 继承硬性规则
-
单继承限制 :一个类只能有唯一父类,不支持 C++ 多继承、菱形继承;
-
可同时实现多个
interface接口,弥补多继承缺失; -
继承语法:
class 子类 : 父类,无需额外权限修饰符; -
成员继承权限规则:
public:子类、外部全部可访问;protected:仅本类 + 子类可访问(继承专用修饰符);private:私有成员无法被子类继承,属于类内部私有资源。
3. base 关键字(核心)
概念
base专门在子类中访问父类资源,等价 Java/TSsuper,C++ 无该关键字。
三大使用场景
-
子类构造函数调用父类构造:
子类构造(参数) : base(父参数); -
子类重写方法内部,调用父类同名方法;
-
访问父类
protected/public成员变量。
代码示例:植物父类 + 向日葵子类
// 父类:通用植物(基类)
class Plant
{
protected string name;
protected int hp;
// 带参构造
public Plant(string n, int h)
{
name = n;
hp = h;
}
// 通用受伤害方法(虚方法,支持重写)
public virtual void OnHit()
{
Console.WriteLine($"{name}受到普通伤害");
}
public void PlayAnim()
{
Console.WriteLine("播放通用植物动画");
}
}
// 子类:向日葵,继承Plant
class SunFlower : Plant
{
// 子类构造,通过base调用父类构造
public SunFlower(string n, int h) : base(n, h) { }
// 子类独有方法
public void CreateSun()
{
Console.WriteLine($"{name}生产阳光");
}
}
// 调用测试
static void Main()
{
SunFlower sf = new SunFlower("向日葵", 100);
sf.PlayAnim(); // 继承父类通用方法
sf.CreateSun(); // 子类独有
sf.OnHit();
}
4. 构造函数继承规则
-
父类有无参构造时,子类实例化自动隐式调用父无参构造;
-
父类只有带参构造、无无参构造 ,子类必须使用
:base(参数)显式调用,否则编译报错; -
执行顺序:先父类构造 → 再子类构造;
-
析构函数执行顺序相反:先子类析构 → 父类析构,析构自动调用,无法手动调用。
5. new 隐藏同名方法
概念
子类定义与父类同名、同参方法,不加override时,编译器提示隐藏警告,添加new关键字显式声明「该方法与父类无关,仅隐藏不重写」,无多态效果。
特性
仅子类变量调用该方法,父类变量指向子类对象时,仍执行父类原函数。
class Plant
{
public void Show() => Console.WriteLine("父类植物信息");
}
class Nut : Plant
{
// new 隐藏父类Show,无多态
public new void Show() => Console.WriteLine("坚果信息");
}
static void Main()
{
Plant p = new Nut();
p.Show(); // 输出父类方法,不会执行子类
}
二、多态(Polymorphism)
1. 分类:静态多态 + 动态多态
(1)静态多态(编译期确定)
概念:程序编译阶段就确定调用哪个函数,代表:函数重载、运算符重载。
规则:同类 / 同作用域,函数名相同、参数个数 / 类型 / 顺序不同,返回值不参与重载区分。
(2)动态多态(运行时确定,本节课重点)
概念
程序运行时,根据对象真实类型自动匹配子类重写的方法,父类引用可统一管理全部子类对象(游戏引擎批量更新脚本核心原理)。
实现必备两个关键字(缺一不可)
-
父类方法标记
virtual:标记为虚方法,允许子类重写; -
子类同名方法标记
override:重写覆盖父虚方法;
动态多态核心规则
1 方法名、参数列表、返回值必须完全一致;
2 父类变量接收子类实例,调用虚方法时自动执行子类override逻辑;
3 仅继承体系、虚方法可实现动态多态。
完整实战代码(坚果重写受伤害逻辑)
class Plant
{
protected string name;
protected int hp;
public Plant(string n, int h)
{
name = n; hp = h;
}
// 虚方法,允许子类重写
public virtual void OnHit()
{
Console.WriteLine($"{name}普通受伤");
}
}
// 坚果子类,重写受伤逻辑
class Nut : Plant
{
public Nut(string n, int h) : base(n, h) { }
// override 重写虚方法,实现动态多态
public override void OnHit()
{
if(hp > 5000)
Console.WriteLine($"{name}轻伤动画");
else if(hp > 2500)
Console.WriteLine($"{name}重伤动画");
else
Console.WriteLine($"{name}破碎消失");
}
}
static void Main()
{
// 父类引用指向子类,多态生效
Plant plant = new Nut("坚果墙", 7500);
plant.OnHit(); // 自动执行子类override方法
}
2. 多态工程价值
游戏引擎中所有脚本继承统一父类(MonoBehaviour/Component),引擎统一遍历父类数组,自动执行每个子类独有的Update()、受伤害逻辑,无需大量 if 判断类型。
三、抽象类 abstract
1. 基础概念
使用abstract修饰的类称为抽象类,用于定义一套统一规范,不能直接 new 实例化,仅能作为父类被子类继承。
2. 两大核心特性
-
抽象类可以包含普通成员、普通虚方法、抽象方法;
-
抽象方法:
abstract 方法签名;只有声明、无函数体,强制非抽象子类必须override实现; -
仅含抽象方法的类必须标记 abstract;抽象类可无抽象方法(仅限制实例化)。
3 硬性规则
-
抽象方法不能私有(private),子类无法重写;仅 public/protected;
-
若子类继承抽象类,但未实现全部抽象方法,该子类也必须标记 abstract;
-
抽象类无法创建对象,只能通过子类实例使用。
代码示例(抽象动物父类)
// 抽象动物类,定义统一行为规范
abstract class Animal
{
protected string name;
public Animal(string n) { name = n; }
// 抽象方法:无实现,子类必须重写
public abstract void Speak();
// 普通通用方法,所有动物复用
public void Move()
{
Console.WriteLine($"{name}移动");
}
}
// 狗子类,实现抽象Speak
class Dog : Animal
{
public Dog(string n) : base(n) { }
public override void Speak()
{
Console.WriteLine($"{name}:汪汪");
}
}
static void Main()
{
// Animal a = new Animal("大象"); // 报错,抽象类不能实例
Animal dog = new Dog("旺财");
dog.Move();
dog.Speak(); // 执行子类实现的抽象方法
}
四、类型判断与转换 is /as
1. is 关键字
概念:
判断对象是否属于某个类 / 子类,返回 bool 布尔值。
语法:
对象 is 类型
Plant p = new Nut("坚果",7500);
if(p is Nut)
Console.WriteLine("该对象是坚果子类");
2. as 安全强制转换
概念:
安全类型转换,转换失败返回null,不会程序崩溃;
语法:
子类类型 变量 = 父对象 as 子类类型
对比普通强转:直接(Nut)p转换失败直接抛异常,as更安全。
Plant p = new Nut("坚果",7500);
Nut nut = p as Nut;
if(nut != null)
nut.OnHit();
五、构造函数 & 析构函数完整执行顺序
1 构造执行流程(从顶层父类 → 子类逐层执行)
-
程序执行
new 子类(); -
优先调用最高层级父类构造;
-
逐层向下,依次执行各级父类构造;
-
最后执行当前子类构造;
2 析构执行流程(销毁时,子类优先)
1 程序退出 / 对象销毁,先执行子类析构;
2 逐层向上,依次调用各级父类析构;
特性
-
析构函数语法
~类名(),无参数、无返回值、不能加访问修饰; -
析构自动执行,无法手动调用;用于释放堆资源、关闭文件 / 网络;
-
继承体系下父类析构建议标记
virtual,防止多态释放内存泄漏。
六、继承、多态综合实战
abstract class Animal{
protected string name;
public Animal(string name) { this.name = name; }
public abstract void Speak();
public void Move() => Console.WriteLine($"{name}移动");
}
class Dog : Animal{
public Dog(string n) : base(n) { }
public override void Speak() => Console.WriteLine($"{name}:汪汪");
}
class Cat : Animal{
public Cat(string n) : base(n) { }
public override void Speak() => Console.WriteLine($"{name}:喵喵");
}
static void Main(){
// 父类数组统一管理所有子类,多态批量调用
Animal[] arr = {
new Dog("旺财"),
new Cat("汤姆")
};
foreach(var ani in arr) {
ani.Move();
ani.Speak(); // 自动匹配子类实现
}
}
七、拓展
1 C# 是否支持多继承?答:类仅单继承,可多实现接口;
2 virtual/override/new 三者区别:
virtual:父类开放重写权限;
override:子类重写虚方法,实现多态;
new:仅隐藏父方法,无运行多态;
3 base 三种使用场景:子类构造、调用父方法、访问父成员;
4 抽象类和普通类区别:抽象类不能实例、含强制实现抽象方法;
5 构造 / 析构执行顺序(笔试题高频);
6 is判断类型、as安全转换,规避强转崩溃;
7 动态多态运行时生效,静态重载编译期生效。