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 须遵守的规则

父类必须允许修改​

方法前要有virtualabstract(像爸爸说"你可以改充电方法")

签名要完全一致​

复制代码
//合法
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)​ ​ 和​​增强灵活性​​。

  • 调用方​​实现方​解耦:调用方只依赖一个稳定的抽象契约,而不关心背后千变万化的具体实现。
  • 是什么​​怎么做​解耦:调用方只知道"要做什么"(调用哪个接口),而具体"怎么做"则由各个对象自己负责。

学到了这里,咱俩真棒,记得按时吃饭(九月至,秋风起,九月会有炒板栗~)

【本篇结束,新的知识会不定时补充】

感谢你的阅读!如果内容有帮助,欢迎 ​​点赞❤️ + 收藏⭐ + 关注​​ 支持! 😊

相关推荐
半路程序员5 小时前
Go语言学习(二)
学习
私人珍藏库7 小时前
[Android] 京墨 v1.15.2 —— 古诗词文、汉语字典、黄历等查询阅读学习宝典(可离线)
android·学习·安卓
悠哉悠哉愿意9 小时前
【数学建模学习笔记】数据标准化
笔记·学习·数学建模
cplmlm11 小时前
WPF+IOC学习记录
c#·wpf
扯淡的闲人11 小时前
Go语言入门学习笔记
笔记·学习·golang
Nita.12 小时前
C# 模式匹配(Pattern Matching)
c#
程序设计实验室12 小时前
重写 StarBlog 的搜索功能和页面,支持权重设置和结果高亮
c#·starblog番外
stjiejieto12 小时前
教育 AI 的下半场:个性化学习路径生成背后,技术如何平衡效率与教育本质?
大数据·人工智能·学习
彭刷子12 小时前
[c语言]简单的进行多次计算的+-*/计算机
c语言·学习