c# 继承和多态详解
技术百科
月夜之吻
发布时间:2026-01-23
浏览: 次 继承是多态的结构基础,多态是继承的行为表现;abstract用于父类只定义契约不实现时,virtual用于提供默认行为且允许覆盖;多态仅在父类引用调用虚/抽象方法时生效。
继承和多态不是两个独立概念,而是一体两面:继承是结构基础,多态是行为表现——没继承,多态无从谈起;没抽象或虚成员,多态就只是普通调用。
什么时候必须用 abstract?
当你在父类中「只定义行为契约,不提供实现」时,就必须用 abstract。比如所有动物都要 MakeSound(),但狗叫、猫叫、鸟鸣各不相同,父类无法写死逻辑。
- 抽象方法必须放在
abstract class中,且子类非抽象时,override是强制的 - 抽象类可以没有抽象方法(比如只做类型约束或共享字段)
- 不能
new抽象类实例,哪怕它有构造函数 - 错误现象:
'Animal' does not implement inherited abstract—— 子类忘了加
member 'Animal.MakeSound()'
override或漏了方法体
什么时候该用 virtual 而不是 abstract?
当父类能提供一个「合理默认行为」,但允许子类按需覆盖时,用 virtual。比如 ToString() 默认返回类型名,子类可重写为返回更友好的格式。
- 虚方法可以被子类
override,也可以不重写,直接沿用父类逻辑 - 子类中若想调用父类原版实现,得显式写
base.MethodName() - 常见误用:把本该是
virtual的方法写成private或sealed,导致子类无法扩展 - 性能影响极小,但过度虚化(比如每个 getter 都
virtual)会轻微增加虚表查找开销,一般无需担心
多态真正生效的两个典型场景
多态不是“写了 override 就自动多态”,它只在「通过父类引用调用虚/抽象方法」时才触发。关键看变量声明类型,不是实际对象类型。
Animal a1 = new Dog(); Animal a2 = new Cat(); Console.WriteLine(a1.MakeSound()); // 输出 "Woof!" Console.WriteLine(a2.MakeSound()); // 输出 "Meow!"
- 参数多态:
void Feed(Animal animal) { animal.Eat(); }—— 传Dog就执行Dog.Eat(),传Bird就执行Bird.Eat() - 返回值多态:
Animal Create(string type) => type switch { "dog" => new Dog(), "cat" => new Cat() };—— 调用方只需按Animal处理,不用关心具体类型 - 容易踩的坑:用子类变量直接调用,比如
Dog d = new Dog(); d.MakeSound();—— 这走的是静态绑定,不触发多态,哪怕方法是virtual或abstract - 注意:只有
virtual、abstract和override成员参与多态;private、static、sealed override均不参与
protected 和 base 在继承链中的真实作用
protected 不是“给子类用的 public”,而是「仅限派生类内部访问」的访问修饰符;base 是子类访问父类成员的唯一安全通道。
-
protected成员可在子类中直接使用(如this.Name),但不能通过子类实例访问(new Dog().Name报错) - 子类构造函数必须显式或隐式调用基类构造函数;若基类无无参构造,子类必须用
: base(...)指定 - 常见错误:
base调用位置不对(必须是构造函数第一行)、或在静态方法里误用base - 不要用
protected暴露内部状态,优先考虑protected virtual方法供子类定制行为,而非暴露字段
最常被忽略的一点:多态依赖运行时类型信息(RTTI),而 .NET 的 JIT 编译器对虚调用做了高度优化,所以别因“怕慢”而回避 virtual —— 真正的性能瓶颈几乎从来不在这里,而在设计失当导致的深层继承链或过度抽象。
# 的是
# 放在
# 重写
# 在这里
# 都要
# 什么时候
# public
# 对象
# String
# void
# class
# c#
# 子类
# 构造函数
# .net
# Static
# private
# this
# 类中
# 继承
# switch
# 多态
# protected
# 父类
# 性能瓶颈
# 引用调用
# 抽象类
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- Python集合操作技巧_高效去重解析【教程】
- Win11 C盘满了怎么清理 Win11磁盘清理和
- 如何在Golang中实现微服务负载均衡_Golan
- php8.4如何实现队列任务_php8.4redi
- php嵌入式需要什么环境_搭建php+linux嵌
- Win11任务栏天气怎么关闭 Win11隐藏天气小
- php能控制zigbee模块吗_php通过串口与c
- Win11怎样彻底卸载自带应用_Win11彻底卸载
- Python模块的__name__属性如何由导入方
- c++怎么实现大文件的分块读写_c++ 文件指针s
- Go 中的 := 运算符:类型推导机制与使用边界详
- LINUX如何删除用户和用户组_Linux use
- Win11怎么更改系统语言_Win11中文语言包下
- Win11怎么设置快速访问主页_Windows11
- MAC如何修改默认应用程序_MAC文件后缀关联设置
- php查询数据怎么分组_groupby分组查询配合
- Python抽象类与接口设计_规范说明【指导】
- Go 语言标准库为何不提供泛型 Contains
- Mac如何修改Hosts文件?(本地开发与屏蔽网站
- 如何使用Golang recover捕获panic
- Win10如何更改用户账户控制_Windows10
- Win11怎么清理C盘下载文件夹_Win11清理下
- c++中如何求一个数的平方根_c++ sqrt函数
- PythonWeb前后端整合项目教程_FastAP
- 如何在Golang中写入XML文件_生成符合规范的
- php8.4匿名类怎么用_php8.4匿名类创建与
- Mac的“预览”如何合并多个PDF_Mac文件处理
- Win11怎么更改账户头像_Windows 11自
- Go语言中slice追加操作的底层共享机制解析
- Win11怎么关闭自动调节亮度_Windows11
- c++中如何进行二进制文件读写_c++ read与
- Win11怎么更改鼠标指针_Windows 11自
- PHP中require语句后直接调用返回对象方法的
- Win10怎么卸载鲁大师_Win10彻底卸载鲁大师
- c++怎么设置线程优先级与cpu亲和性_c++ 多
- Win10如何备份驱动程序_Win10驱动备份步骤
- MySQL 中使用 IF 和 CASE 实现查询字
- Win11怎么设置虚拟键盘_打开Win11屏幕键盘
- 如何减少Golang内存碎片化_Golang内存分
- c++怎么处理多线程死锁_c++ lock_gua
- Win11怎么开启游戏工具栏_Windows11
- php删除数据怎么加限制_带where条件删除避免
- Python网络异常模拟_测试说明【指导】
- c# 在高并发下使用反射发射(Reflection
- Win11怎么格式化U盘_Win11系统U盘格式化
- SAX解析器是什么,它与DOM在处理大型XML文件
- Windows10电脑怎么设置防火墙出站规则_Wi
- 如何在 Django 中修改用户密码后保持会话不丢
- Win11键盘快捷键大全_Windows 11常用
- php485支持哪些操作系统_php485跨系统支


QQ客服