深入理解C#中abstract与virtual关键字的区别及使用

周末不加班
周末不加班
发布时间:2026-10-15 | 5人浏览过
原创

在C#面向对象编程中,abstract和virtual是实现多态性的两大基石。前者强制子类提供具体实现,后者允许子类选择性覆盖原有行为。理解两者的机制差异及override关键字的作用,是编写健壮继承体系的关键。

核心概念与区别

abstract(抽象)关键字用于修饰类或成员。抽象类不能被实例化,且包含抽象方法时必须由子类通过override提供实现。它通常用于定义基类的通用接口标准。

virtual(虚拟)关键字用于修饰方法、属性或事件。被标记为virtual的成员提供了默认实现,并允许派生类使用override关键字来修改其行为。如果派生类未进行重写,则调用基类的默认实现。

特性abstractvirtual
是否必须提供实现是(对抽象成员而言)否(提供默认实现)
能否被实例化不能(抽象类)能
派生类处理方式必须override可选择override

虚方法与重写的运行机制

为了清晰展示virtual与override的工作流程,以下示例展示了从基类到多层继承的调用逻辑。注意new关键字会隐藏而非重写虚方法。

复制代码 代码如下:
class A 
{
    public virtual void Func() 
    {
        Console.WriteLine("Func In A");
    }
}

// B类继承A,并重写虚方法
class B : A 
{
    public override void Func() 
    {
        Console.WriteLine("Func In B");
    }
}

// C类继承B,但未重写Func()
class C : B 
{
}

// D类继承A,但使用new隐藏父类方法,非真正重写
class D : A 
{
    public new void Func() 
    {
        Console.WriteLine("Func In D");
    }
}

class Program 
{
    static void Main(string[] args) 
    {
        // 定义对象及其类型
        A a = new A(); 
        A b = new B(); 
        A c = new C(); 
        A d = new D(); 

        // 测试调用结果
        a.Func(); // 输出: Func In A
                  // 解析:实例类A无重写,执行基类A的实现

        b.Func(); // 输出: Func In B
                  // 解析:实例类B有override,执行B的实现

        c.Func(); // 输出: Func In B
                  // 解析:实例类C无重写,向上查找父类B,执行B的实现

        d.Func(); // 输出: Func In A
                  // 解析:尽管D中有Func,但因使用new隐藏,此处按引用类型A查找,
                  // 且D中的Func不是override,故执行A的实现。

        // 若直接以D类型调用
        D d1 = new D();
        d1.Func(); // 输出: Func In D
                   // 解析:此时编译时类型为D,直接调用D中的隐藏方法

        Console.ReadLine();
    }
}

第1步:识别虚方法入口

在基类中声明方法时使用public virtual void MethodName()。这告诉编译器该方法的实际版本可能在运行时确定,需保留分派槽(vtable slot)。

第2步:选择性地重写方法

在派生类中,如果希望改变行为,必须使用public override void MethodName()。这确保了当基类引用指向派生类对象时,调用的是派生类的实现,体现多态性。

第3步:处理隐藏与非重写情况

如果在派生类中使用public new void MethodName(),这将创建一个全新的方法,隐藏基类的虚方法。此时,多态性失效。例如上面的D类,当以A类型引用d时,调用d.Func()>仍会进入A的逻辑,因为D并没有参与虚表的分发。

总结与应用建议

在设计类层次结构时,若要求所有子类必须实现特定逻辑,请使用abstract;若基类可提供通用逻辑但允许特殊定制,请使用virtual配合override。避免随意使用new隐藏虚方法,除非你明确希望切断多态链,否则这往往是设计上的反模式。

以上就是关于C#中abstract和virtual关键字的详细解析,更多关于C#进阶技巧的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表