c# 继承和多态详解

发布时间 - 2026-01-23 00:00:00    点击率:
继承是多态的结构基础,多态是继承的行为表现;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 的方法写成 privatesealed,导致子类无法扩展
  • 性能影响极小,但过度虚化(比如每个 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(); —— 这走的是静态绑定,不触发多态,哪怕方法是 virtualabstract
  • 注意:只有 virtualabstractoverride 成员参与多态;privatestaticsealed override 均不参与

protectedbase 在继承链中的真实作用

protected 不是“给子类用的 public”,而是「仅限派生类内部访问」的访问修饰符;base 是子类访问父类成员的唯一安全通道。

  • protected 成员可在子类中直接使用(如 this.Name),但不能通过子类实例访问(new Dog().Name 报错)
  • 子类构造函数必须显式或隐式调用基类构造函数;若基类无无参构造,子类必须用 : base(...) 指定
  • 常见错误:base 调用位置不对(必须是构造函数第一行)、或在静态方法里误用 base
  • 不要用 protected 暴露内部状态,优先考虑 protected virtual 方法供子类定制行为,而非暴露字段

最常被忽略的一点:多态依赖运行时类型信息(RTTI),而 .NET 的 JIT 编译器对虚调用做了高度优化,所以别因“怕慢”而回避 virtual —— 真正的性能瓶颈几乎从来不在这里,而在设计失当导致的深层继承链或过度抽象。


# switch  # c#  # 性能瓶颈  # .net  # Static  # String  # 多态  # 父类  # 子类  # 构造函数  # 引用调用  # void  # 继承  # class  # public  # private  # protected  # 对象  # this  # 什么时候  # 类中  # 重写  # 的是  # 在这里  # 放在  # 抽象类  # 都要 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: PHP怎么接收前端传的文件路径_处理文件路径参数接收方法【汇总】  iOS UIView常见属性方法小结  魔毅自助建站系统:模板定制与SEO优化一键生成指南  香港服务器网站推广:SEO优化与外贸独立站搭建策略  如何用搬瓦工VPS快速搭建个人网站?  高防服务器如何保障网站安全无虞?  javascript事件捕获机制【深入分析IE和DOM中的事件模型】  再谈Python中的字符串与字符编码(推荐)  Laravel怎么创建控制器Controller_Laravel路由绑定与控制器逻辑编写【指南】  Python文件异常处理策略_健壮性说明【指导】  如何快速搭建高效简练网站?  Python高阶函数应用_函数作为参数说明【指导】  Java垃圾回收器的方法和原理总结  如何挑选最适合建站的高性能VPS主机?  高性价比服务器租赁——企业级配置与24小时运维服务  Laravel如何实现多表关联模型定义_Laravel多对多关系及中间表数据存取【方法】  Laravel如何处理和验证JSON类型的数据库字段  如何在搬瓦工VPS快速搭建网站?  PHP 500报错的快速解决方法  如何用景安虚拟主机手机版绑定域名建站?  如何在建站之星绑定自定义域名?  网站制作免费,什么网站能看正片电影?  详解Huffman编码算法之Java实现  php485函数参数是什么意思_php485各参数详细说明【介绍】  公司网站制作价格怎么算,公司办个官网需要多少钱?  详解Nginx + Tomcat 反向代理 如何在高效的在一台服务器部署多个站点  Laravel怎么使用Markdown渲染文档_Laravel将Markdown内容转HTML页面展示【实战】  宙斯浏览器文件分类查看教程 快速筛选视频文档与图片方法  Zeus浏览器网页版官网入口 宙斯浏览器官网在线通道  Swift中循环语句中的转移语句 break 和 continue  东莞市网站制作公司有哪些,东莞找工作用什么网站好?  大连网站制作费用,大连新青年网站,五年四班里的视频怎样下载啊?  Laravel如何使用Blade组件和插槽?(Component代码示例)  Internet Explorer官网直接进入 IE浏览器在线体验版网址  Python3.6正式版新特性预览  原生JS实现图片轮播切换效果  linux top下的 minerd 木马清除方法  如何在自有机房高效搭建专业网站?  Laravel辅助函数有哪些_Laravel Helpers常用助手函数大全  如何快速搭建高效香港服务器网站?  JS弹性运动实现方法分析  大同网页,大同瑞慈医院官网?  Laravel Seeder填充数据教程_Laravel模型工厂Factory使用  EditPlus中的正则表达式 实战(2)  如何将凡科建站内容保存为本地文件?  如何在HTML表单中获取用户输入并结合JavaScript动态控制复利计算循环  HTML透明颜色代码怎么让图片透明_给img元素加透明色的技巧【方法】  Win11怎么更改系统语言为中文_Windows11安装语言包并设为显示语言  油猴 教程,油猴搜脚本为什么会网页无法显示?  齐河建站公司:营销型网站建设与SEO优化双核驱动策略