C#知识学习-012(修饰符)
1.abstract(抽象)
1.1 概念
最简核心概念:abstract
:表示“不完整”或“需要别人补全”。
核心特征:不可实例化;混合成员类型(已实现成员 + 未实现抽象成员);强制实现
想象你要组装一辆玩具车:
抽象类 = 半成品玩具套件
- 盒子里有部分组装好的车身(已实现的功能)
- 但缺少方向盘和轮子(抽象成员)
- 不能直接玩这个半成品!(抽象类不能实例化)
具体类 = 你组装完成的玩具车
- 你必须装上方向盘和轮子(派生非抽象类必须实现父类所有抽象成员)
- 现在可以快乐玩耍了!
代码示例:
static void Main() { // 错误!不能玩半成品 // ToyCarKit kit = new ToyCarKit(); // 正确!玩组装好的法拉利 Ferrari myCar = new Ferrari(); myCar.LightUp(); // 使用半成品自带的灯光功能,输出:车灯亮啦 myCar.AddWheels(); // 使用你自己实现的轮子功能,输出:装上了4个轮子}// 半成品玩具车套件(抽象类)abstract class ToyCarKit { // 已组装好的部分 public void LightUp() { Console.WriteLine(\"车灯亮啦\"); } // 缺失的关键零件(抽象成员) public abstract void AddWheels(); // 必须你自己装轮子}// 你组装完成的法拉利玩具车class Ferrari : ToyCarKit { // 你必须自己装轮子!(实现抽象方法) public override void AddWheels() { Console.WriteLine(\"装上了4个轮子\"); }}
1.2 构造函数参数
- 当构造函数参数没有默认值时:
abstract class Animal { protected Animal(string name) {} // 无默认值}class Dog : Animal { public Dog() : base(\"Buddy\") {} // 必须传名字}// 使用var dog = new Dog(); // 名字固定为\"Buddy\"
- 当构造函数参数有默认值时(不传参):
abstract class Animal { protected Animal(string name = \"Animal\") {} // 有默认值}class Dog : Animal { public Dog() {} // 自动使用默认名字\"Animal\"}// 使用var dog = new Dog(); // 名字默认为\"Animal\"
- 当构造函数参数有默认值时(传参):
abstract class Animal{ protected Animal(string name = \"Animal\"){}}class Dog : Animal{ // 自己传递参数给基类 public Dog(string customName) : base(customName) {} }// 使用var myDog = new Dog(\"旺财\"); // 创建时自己命名
2.virtual
2.1 概念
virtual
关键字:用于方法、属性、索引器或事件,允许它们在派生类(子类)中被重写(override)。这意味着父类中的方法或属性可以在子类中被替换成新的实现。
重写是什么意思?
比如,你有一个形状类(Shape),它有一个计算面积的方法。但是不同的形状(比如圆形、矩形)计算面积的方法不一样。你可以在形状类中定义一个虚方法,然后在子类中根据具体的形状重写这个方法。
为什么使用virtual?
当你在父类中定义了一个方法,但是这个方法在子类中可能有不同的行为时。
子类可以使用override
关键字来提供自己的实现。
代码示例:
static void Main(){ Dog dog = new Dog(); dog.MakeSound(); // 输出:汪汪汪! Cat cat = new Cat(); cat.MakeSound(); // 输出:喵喵喵! Animal animal = new Animal(); animal.MakeSound(); // 输出:动物发出叫声}class Animal{ // 基类中声明一个虚方法 public virtual void MakeSound() { Console.WriteLine(\"动物发出叫声\"); }}class Dog : Animal{ // 重写基类的虚方法 public override void MakeSound() { Console.WriteLine(\"汪汪汪!\"); }}class Cat : Animal{ public override void MakeSound() { Console.WriteLine(\"喵喵喵!\"); }}
Animal myPet = new Dog(); // 常见场景:用基类引用子类对象myPet.MakeSound(); // 输出:汪汪汪!(自动调用子类实现)
注意事项:
- 默认情况下,方法是非虚拟的(非virtual),也就是说不能重写。
- 只有在父类中声明为
virtual
(或abstract
)的方法,才能在子类中被重写。
2.2 使用场景
- 多个子类需要同功能不同实现(如支付方式:微信/支付宝)
- 需要统一接口但细节不同(如不同数据库的连接方式)
- 设计可扩展框架(比如游戏中的技能系统)
我来解释一下:
- 统一操作入口:不管有多少种动物,只需要记住一个方法名:
MakeSound()
- 自动适配实现:小狗对象自动返回汪汪汪,小猫对象自动返回喵喵喵
- 扩展方便:添加新动物只需继承+重写,不用改现有代码
3.override
3.1 概念
override
是什么:当子类想修改或替换父类方法的行为时使用的关键字
为什么需要:父类定义基础能力;子类实现具体行为
代码示例:
//爸爸的充电方法 (普通充电)Class DadCharging{ Public virtual void charging () // 允许儿子修改 { Console. WriteLine (\"5V慢充\"); }}//儿子的充电宝 (增强版)Class SonFastCharging : DadCharging{ Public override void charging () // 明确要修改 { Console. WriteLine (\"50W快充\")); // 修改了具体行为 }}
3.2 须遵守的规则
父类必须允许修改:
方法前要有virtual
或abstract
(像爸爸说\"你可以改充电方法\")
签名要完全一致:
//合法public override int 方法名(参数) {...} //非法 (参数不同)public override int 方法名(int 新参数) {...}
访问权限不能更严格:
如果父类方法是public
,重写时不能改成private
什么时候必须用?
当你看到这些关键词时:
👉 abstract
(父类说\"我这功能没实现,你必须自己写\")
👉 virtual
(父类说\"我有默认实现,但你可以改\")
比如:
abstract class Animal{ public abstract void speak(); // 抽象方法:必须override public virtual void run() { ... } // 虚方法:可override}
常见误区:
错误:想重写普通方法
class Parent { public void Foo() {} // 普通方法}class Child : Parent { public override void Foo() {} // 编译报错!}
解决方案:用new
关键字
public new void Foo() { ... } // 新方法不会影响父类
补充:多态
多态的核心定义:多态是面向对象编程的三大特性之一(封装、继承、多态),指同一操作作用于不同类的实例时,能产生不同的执行结果。其核心在于:
- 接口统一性:通过基类或接口定义的统一操作规范
- 行为差异化:各子类提供自己对该操作的具体实现
- 运行时绑定:具体执行哪个实现由对象的实际类型决定
在C#中主要通过以下方式实现子类型多态:
- 虚方法(virtual):在基类中声明可被派生类修改的方法
- 重写(override):在派生类中重新定义虚方法的具体实现
- 抽象方法(abstract):强制派生类必须实现的方法(隐式虚方法)
多态的终极目标是实现解耦(Decoupling) 和增强灵活性。
- 调用方与实现方解耦:调用方只依赖一个稳定的抽象契约,而不关心背后千变万化的具体实现。
- 是什么与怎么做解耦:调用方只知道“要做什么”(调用哪个接口),而具体“怎么做”则由各个对象自己负责。
学到了这里,咱俩真棒,记得按时吃饭(九月至,秋风起,九月会有炒板栗~)
【本篇结束,新的知识会不定时补充】
感谢你的阅读!如果内容有帮助,欢迎 点赞❤️ + 收藏⭐ + 关注 支持! 😊