news 2026/4/16 4:27:14

抽象类,抽象与虚方法对比

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
抽象类,抽象与虚方法对比

抽象类关键概念总结

📌什么是抽象类?

  • 使用abstract关键字定义的类

  • 不能被实例化(不能new

  • 用于为派生类提供部分实现的蓝图

🔑抽象类的特点

1. 包含多种成员

csharp

public abstract class People { // 1. 普通字段/属性(可以有默认值) public int Age { get; set; } = 10; // 2. 抽象属性(不能有默认值) public abstract string Name { get; set; } // 3. 普通方法(可以有实现) public void Eat() { Console.WriteLine("吃相难看"); } // 4. 抽象方法(不能有实现) public abstract void SayHello(int a); // 5. 构造函数 public People() { } // 6. 事件、索引器等... }

2. 抽象成员的规则

  • 抽象方法:只有声明,没有方法体(不能加{}

  • 抽象属性:只有声明,不能赋值初始化

  • 抽象成员必须在派生类中使用override实现

  • 如果一个类包含抽象成员,该类必须声明为abstract

3. 继承规则

csharp

// 正确:非抽象类继承抽象类,必须实现所有抽象成员 public class China : People { public override string Name { get; set; } = "南京博物馆火了"; public override void SayHello(int a) { Console.WriteLine("你好 吃了么"); } } // 错误:抽象类继承抽象类,可以不实现抽象成员 public abstract class Asian : People { // 可以不实现 Name 和 SayHello // 但 Asian 类也必须声明为 abstract }

🎯抽象类 vs 接口 vs 普通类

特性抽象类接口普通类
实例化❌ 不能❌ 不能✅ 能
实现继承✅ 单继承✅ 多实现✅ 单继承
包含实现✅ 可以❌ C#8.0前不能✅ 必须
字段/属性✅ 可以有❌ 不能有字段✅ 可以有
构造函数✅ 可以有❌ 不能有✅ 必须有
访问修饰符各种都可以默认 public各种都可以

💡抽象类的核心用途

1. 实现"动态多态"

csharp

// 父类引用指向子类对象 People p1 = new China(); People p2 = new Japan(); p1.SayHello(1); // 输出:你好 吃了么 p2.SayHello(1); // 输出:口你急哇 // 同一个方法调用,不同对象表现不同 → 多态

2. 提供通用模板

csharp

public abstract class Shape { // 所有图形都有颜色 public string Color { get; set; } // 所有图形都能计算面积,但具体算法不同 public abstract double GetArea(); // 所有图形都能显示,显示方式相同 public void Display() { Console.WriteLine($"颜色:{Color},面积:{GetArea()}"); } } public class Circle : Shape { public double Radius { get; set; } public override double GetArea() => Math.PI * Radius * Radius; } public class Square : Shape { public double Side { get; set; } public override double GetArea() => Side * Side; }

3. 强制派生类实现特定功能

csharp

public abstract class DatabaseConnector { // 每个数据库连接器都必须实现连接方法 public abstract void Connect(); public abstract void Disconnect(); // 提供通用的事务处理 public void BeginTransaction() { /* 通用实现 */ } }

⚠️重要注意事项

1. 构造函数调用链

csharp

public abstract class Animal { public Animal(string name) // 抽象类可以有构造函数 { Name = name; } public string Name { get; } } public class Dog : Animal { public Dog(string name) : base(name) // 必须调用基类构造函数 { } }

2. sealed 与 abstract 不能同时使用

csharp

// ❌ 错误:sealed abstract class MyClass { } // sealed 表示"不能继承",abstract 表示"必须继承" → 矛盾

3. 抽象类的设计原则

  1. Is-A关系:继承抽象类的类应该是"一种"抽象类

  2. 共性提取:将多个类的共同点提取到抽象类中

  3. 强制规范:确保派生类必须实现某些关键功能

  4. 代码复用:通过基类实现减少代码重复

📝代码示例:完整抽象类应用

csharp

using System; // 抽象类:支付处理器 public abstract class PaymentProcessor { // 普通属性 public decimal Amount { get; set; } public DateTime PaymentDate { get; set; } = DateTime.Now; // 抽象属性 public abstract string PaymentType { get; } // 普通方法 public void LogPayment() { Console.WriteLine($"支付日志:{PaymentDate} - {Amount}元"); } // 抽象方法 public abstract bool ProcessPayment(); public abstract string GetReceipt(); } // 具体实现:支付宝支付 public class AlipayProcessor : PaymentProcessor { public override string PaymentType => "支付宝"; public override bool ProcessPayment() { Console.WriteLine($"支付宝支付{Amount}元..."); return true; // 模拟支付成功 } public override string GetReceipt() { return $"支付宝支付凭证 - 金额:{Amount}元"; } } // 具体实现:微信支付 public class WechatPayProcessor : PaymentProcessor { public override string PaymentType => "微信支付"; public override bool ProcessPayment() { Console.WriteLine($"微信支付{Amount}元..."); return true; } public override string GetReceipt() { return $"微信支付凭证 - 金额:{Amount}元"; } } class Program { static void Main() { PaymentProcessor[] payments = { new AlipayProcessor { Amount = 100 }, new WechatPayProcessor { Amount = 200 } }; foreach (var payment in payments) { payment.LogPayment(); payment.ProcessPayment(); Console.WriteLine(payment.GetReceipt()); Console.WriteLine(); } } }

🏆总结要点

  1. 抽象类是"半成品"类,需要派生类完成实现

  2. 抽象类 = 接口 + 部分实现

  3. 适用于有层次关系的类设计

  4. 通过抽象类实现模板方法设计模式

  5. 比接口更强大(可以有实现、字段、构造函数等)

抽象类是面向对象设计中实现多态和代码复用的重要工具!

📊抽象方法与虚方法对比总结

1. 定义位置

  • 抽象方法:只能定义在抽象类 (abstract class) 中

  • 虚方法:可以定义在普通类、抽象类、虚类中

2. 实现要求

  • 抽象方法:在抽象类中不能有实现(只有声明)

  • 虚方法:在基类中可以有默认实现

3. 派生类要求

  • 抽象方法:在非抽象的派生类中必须被重写(否则该类也必须声明为抽象类)

  • 虚方法:在派生类中可以重写(可选),也可以不重写

4. 关键字

  • 抽象方法abstract声明,override重写

  • 虚方法virtual声明,override重写

5. 重写方式

csharp

// 抽象方法 public abstract void Method(); // 声明 public override void Method() { } // 重写 // 虚方法 public virtual void Method() { } // 声明+实现 public override void Method() { } // 重写(可选)

6. 实例化

  • 抽象类:不能被实例化(包含抽象方法的类)

  • 虚方法所在的类:可以被实例化(如果没有其他抽象成员)

🎯代码示例对比

csharp

// 抽象方法示例 public abstract class Animal { public abstract void Eat(); // 只有声明,没有实现 } public class Dog : Animal { public override void Eat() // 必须实现 { Console.WriteLine("Dog eats bone"); } } // 虚方法示例 public class People { public virtual void Eat() // 有默认实现 { Console.WriteLine("People eat food"); } } public class Chinese : People { public override void Eat() // 可选重写 { Console.WriteLine("Chinese eat rice"); } } public class American : People { // 不重写,使用基类的默认实现 }

⚠️new 关键字 vs override

csharp

public class Base { public virtual void Method() { Console.WriteLine("Base"); } } public class Derived1 : Base { public override void Method() { Console.WriteLine("Derived1"); } // 重写虚方法 } public class Derived2 : Base { public new void Method() { Console.WriteLine("Derived2"); } // 新建方法,隐藏基类方法 } // 使用 Base obj1 = new Derived1(); Base obj2 = new Derived2(); obj1.Method(); // 输出: Derived1 (多态生效) obj2.Method(); // 输出: Base (new 隐藏,多态不生效)

🏆总结表格

特性抽象方法虚方法
定义位置抽象类中任意类中
实现要求无实现可有默认实现
派生类要求必须实现可选重写
关键字abstract/overridevirtual/override
多态支持
实例化类不能实例化类可实例化

💡使用建议

  1. 需要强制派生类实现→ 用抽象方法

  2. 提供默认实现,允许派生类修改→ 用虚方法

  3. 实现多态→ 用override

  4. 隐藏基类方法(不推荐)→ 用new

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/1 5:57:17

通达信正版庄见愁+海底活鱼

{}KS13:(C-SMA(C,13,1))/SMA(C,13,1)*(-100); {} AAA:REF(KS13,1)>13 AND REF(KS13,1)/KS13>1.23 AND C/REF(C,1)>1.03; 海底活鱼:IF(AAA AND REF(C,1)<COST(5),30,0),COLORWHITE,LINETHICK2; STICKLINE(庄筹线>散筹线,庄筹线,散筹线,0,0),COLORRED;

作者头像 李华
网站建设 2026/4/15 0:11:41

51的复位电路和时钟电路

对于模电数电没啥基础的人&#xff0c;电路一下真看不懂一、复位电路时间常数R*C10k*10u10*1000*0.1*0.001*0.0010.001s1ms1000us给RST引脚两个机器周期以上的高电平&#xff0c;复位。对于12M晶振&#xff0c;机器周期是1us&#xff08;微秒&#xff09;&#xff0c;1000us远大…

作者头像 李华
网站建设 2026/4/11 20:00:31

医疗时序预测漏长程依赖后来补Transformer才稳住趋势

&#x1f4dd; 博客主页&#xff1a;jaxzheng的CSDN主页 目录医疗数据科学&#xff1a;当Excel表格遇见听诊器 一、数据洪流里的"急诊室" 二、算法模型的"成长日记" 三、数据安全的"罗生门" 四、未来展望&#xff1a;当AI成为"全能医生&quo…

作者头像 李华
网站建设 2026/4/14 21:25:08

SSM小微企业ERP软件物料需求模块设计55ss9(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面

系统程序文件列表系统项目功能&#xff1a;bom管理,订单信息,库存管理,mps信息,mrp信息基于 SSM 的小微企业 ERP 软件物料需求模块设计与实现一、研究背景与意义1. 研究背景随着小微企业数字化转型加速&#xff0c;传统的物料管理方式&#xff08;手工台账、Excel 记录&#xf…

作者头像 李华
网站建设 2026/4/13 10:50:02

一键隐藏,简直绝了!

软件介绍 男生电脑里总有些“小秘密”&#xff08;女生好像没有&#xff09;&#xff0c;这些“小秘密”最怕妈妈或者女朋友这类的人看到&#xff0c;所以最好的办法是把这些文件或者文件夹隐藏起来。 今天推荐的这两款软件是两年前我就推荐过的&#xff0c;今天再找出来的时候…

作者头像 李华
网站建设 2026/4/14 20:03:37

【每日算法】LeetCode 79. 单词搜索

对前端开发者而言&#xff0c;学习算法绝非为了“炫技”。它是你从“页面构建者”迈向“复杂系统设计者”的关键阶梯。它将你的编码能力从“实现功能”提升到“设计优雅、高效解决方案”的层面。从现在开始&#xff0c;每天投入一小段时间&#xff0c;结合前端场景去理解和练习…

作者头像 李华