C#的override关键字如何重写虚方法?有什么要求?

星降
发布: 2025-08-20 10:50:02
原创
1042人浏览过
override关键字用于子类重写基类的virtual、abstract或override成员,实现多态;要求方法签名完全匹配,且基类成员必须可被重写;与new关键字不同,override实现运行时多态,而new是方法隐藏;重写时可通过base调用基类实现,常用于扩展而非替换行为;还可结合sealed防止进一步重写。

c#的override关键字如何重写虚方法?有什么要求?

C#中,

override
登录后复制
关键字的职责是让子类重新实现(重写)其基类中已声明为
virtual
登录后复制
abstract
登录后复制
或本身已是
override
登录后复制
的方法、属性、索引器或事件。它的核心要求是方法签名必须完全匹配基类,并且基类成员必须是可被重写的。

解决方案

当我们谈论

override
登录后复制
,其实是在拥抱多态性。这就像你有一个通用的概念——比如“交通工具的移动方式”,但具体到汽车、飞机、船,它们的“移动”行为是完全不同的。在C#里,如果你定义了一个
Vehicle
登录后复制
基类,里面有个
Move()
登录后复制
方法,但你不想在基类里写死所有交通工具的移动逻辑,于是你把
Move()
登录后复制
标记为
virtual
登录后复制
。这意味着,我提供一个默认的移动方式(或者干脆不提供,如果是
abstract
登录后复制
),但允许我的子类根据自己的特性去重新定义这个“移动”的具体细节。

子类,比如

Car
登录后复制
Airplane
登录后复制
,就可以各自
override
登录后复制
这个`
Move()
登录后复制
方法,实现它们独特的移动方式。

public class Vehicle
{
    // virtual 关键字表示这个方法可以被子类重写
    public virtual void Move()
    {
        Console.WriteLine("Vehicle is moving.");
    }
}

public class Car : Vehicle
{
    // override 关键字表示重写基类的 Move 方法
    public override void Move()
    {
        // 可以选择调用基类实现,也可以完全替换
        // base.Move(); 
        Console.WriteLine("Car is driving on the road.");
    }
}

public class Airplane : Vehicle
{
    public override void Move()
    {
        Console.WriteLine("Airplane is flying in the sky.");
    }
}

// 实际使用
// Vehicle myCar = new Car();
// myCar.Move(); // 输出:Car is driving on the road.
// Vehicle myPlane = new Airplane();
// myPlane.Move(); // 输出:Airplane is flying in the sky.
登录后复制

这让我们的代码变得异常灵活和可扩展。你可以用一个基类引用来操作不同类型的对象,而运行时会根据实际对象的类型来调用正确的方法。这种“一个接口,多种实现”的哲学,正是面向对象编程的魅力所在。

使用
override
登录后复制
关键字有哪些前提条件?

要成功地使用

override
登录后复制
,可不是随便就能来的,它有一些明确的“规矩”。

首先,被重写的方法、属性或事件在基类中必须明确地被标记为

virtual
登录后复制
abstract
登录后复制
,或者它本身就是从更上层的基类
override
登录后复制
下来的。如果你尝试去重写一个既不是
virtual
登录后复制
也不是
abstract
登录后复制
的方法,或者一个被
sealed
登录后复制
(密封)了的方法,编译器会直接报错。这就像是基类在说:“我允许你改变我的行为”,或者“我要求你实现这个行为”,否则子类就没有重写的权利。

其次,方法签名必须完全匹配。这意味着什么?就是方法的名称、参数的类型和数量、参数的顺序,甚至返回值类型,都必须和基类中被重写的方法一模一样。这是语言层面在强制一种契约:你承诺了要提供这个功能,但具体实现可以变。如果签名不一致,那就不叫重写了,那叫定义了一个全新的方法,即使名字相同。

访问修饰符也得保持一致,或者在子类中可以放宽。比如,基类中的

virtual
登录后复制
方法是
protected
登录后复制
,那么在子类中重写时,可以是
protected
登录后复制
,也可以是
public
登录后复制
。但你不能把它变成
private
登录后复制
,因为那样就限制了基类接口的可见性,这显然是违背了继承的初衷。

override
登录后复制
new
登录后复制
关键字有何不同?

初学C#时,很多人会混淆

override
登录后复制
new
登录后复制
这两个关键字。它们都能让子类拥有一个与基类同名的方法,但背后的机制和意图却截然不同。

阿里云-虚拟数字人
阿里云-虚拟数字人

阿里云-虚拟数字人是什么? ...

阿里云-虚拟数字人2
查看详情 阿里云-虚拟数字人

new
登录后复制
关键字,当它用于子类方法时,表示你正在子类中定义一个全新的方法,这个方法恰好与基类中的某个方法同名。这被称为“方法隐藏”(Method Hiding),而不是重写。当使用
new
登录后复制
时,哪个方法被调用,取决于你声明变量的类型,而不是实际对象的类型。

举个例子:

public class BaseClass
{
    public void Show()
    {
        Console.WriteLine("BaseClass Show");
    }
}

public class DerivedClass : BaseClass
{
    public new void Show() // 使用 new 隐藏基类的 Show 方法
    {
        Console.WriteLine("DerivedClass Show");
    }
}

// BaseClass b = new DerivedClass();
// b.Show(); // 输出:BaseClass Show (因为变量类型是 BaseClass)

// DerivedClass d = new DerivedClass();
// d.Show(); // 输出:DerivedClass Show (因为变量类型是 DerivedClass)
登录后复制

override
登录后复制
则完全不同。它真正实现了运行时多态性。无论你用基类引用还是子类引用来调用方法,C#运行时都会根据实际对象的类型来决定调用哪个方法。这才是我们追求的面向对象灵活性,因为它保持了类型之间的继承关系和行为契约。我个人觉得,如果你想扩展或改变基类的行为,
override
登录后复制
几乎总是你的首选,因为它维护了类之间的逻辑关联和多态性。
new
登录后复制
更多是在你无法修改基类,但又需要一个同名方法时的一种妥协方案,它打破了多态的链条。

在重写方法中调用基类实现有哪些常见场景?

使用

override
登录后复制
时,一个非常常见的“技巧”或者说“设计模式”是是否调用
base
登录后复制
实现。
base
登录后复制
关键字允许你在子类重写的方法中显式地调用基类的同名方法。这并非强制,但很多时候它能带来巨大的便利和更优雅的设计。

一个典型的场景是扩展基类的行为,而不是完全替换它。比如,你有一个

LogMessage
登录后复制
方法,基类可能只负责把消息写入控制台,而子类可能想在写入控制台的同时,也把消息写入文件或者发送到某个监控系统。这时,你可以在子类中先调用
base.LogMessage()
登录后复制
来完成基类的功能,然后再添加子类特有的日志记录逻辑。

public class Logger
{
    public virtual void Log(string message)
    {
        Console.WriteLine($"[Console Log]: {message}");
    }
}

public class FileLogger : Logger
{
    public override void Log(string message)
    {
        // 先调用基类的日志功能
        base.Log(message); 
        // 再添加子类特有的文件日志功能
        System.IO.File.AppendAllText("log.txt", $"[File Log]: {message}\n");
        Console.WriteLine($"[File Logged]: {message}");
    }
}

// Logger myLogger = new FileLogger();
// myLogger.Log("This is a test message.");
// 输出:
// [Console Log]: This is a test message.
// [File Logged]: This is a test message.
// 同时,消息也会被写入 log.txt 文件
登录后复制

另一个场景是初始化或清理。比如,你有一个复杂的对象初始化过程,基类负责通用的初始化,而子类需要在此基础上进行一些特定的设置。在子类的构造函数或初始化方法中,调用

base
登录后复制
的对应方法,确保基类的状态正确建立,然后再进行子类特有的初始化。

但也要注意,不是所有情况都需要调用

base
登录后复制
。有时你就是想完全替换基类的行为,比如前面
Vehicle
登录后复制
的例子,
Car
登录后复制
Move
登录后复制
方法就完全不需要调用
base.Move()
登录后复制
,因为它有自己独特的移动方式。

最后,值得一提的是

sealed
登录后复制
关键字。如果你在重写一个方法时,不希望这个方法在更深层次的子类中再次被重写,就可以在
override
登录后复制
的同时加上
sealed
登录后复制
修饰符。这就像是说:“到我这儿,这个方法的重写就此为止了,下面的子类不能再改了。”这在设计框架或库时特别有用,可以防止不必要的行为篡改,确保某些核心逻辑的稳定性。

以上就是C#的override关键字如何重写虚方法?有什么要求?的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号