美文网首页
C# abstract virtual sealed

C# abstract virtual sealed

作者: 合肥黑 | 来源:发表于2022-01-25 09:49 被阅读0次

    参考
    简单易懂的解释c#的abstract和virtual的用法和区别

    一、abstract

    先来看abstract方法,顾名思义,abstract方法就是抽象方法。抽象方法就是没有实现的,必须是形如:

    public abstract void Init();
    

    拥有抽象方法的类必须修饰一个abstract关键字从而变成一个抽象类;但是反过来,抽象类里面不一定要有抽象方法,比如我写了一个非抽象类,但是这个类我不想让人直接实例化,而只让人继承,我就可以把他变成一个抽象类,虽然他里面并没有抽象方法。形如:

    abstract class TestAbstractSuper
    
    • 抽象类不能被实例化,只能被继承。
    • 抽象类的子类必须实现每个抽象方法。
    • 抽象类里面除了可以有抽象方法以外,也可以有普通的方法。
    • 抽象类的构造函数可以省略,编译器会自动加上,但是不能是一个抽象方法,而只能是一个普通的构造函数。

    小结:简单概括一下,抽象类不可以直接实例化,他可以有n个(n>=0)抽象方法,这些抽象方法子类必须实现。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
     
    using System.Diagnostics;
     
    namespace TestAppAllHere
    {
        abstract class TestAbstractSuper
        {
            public TestAbstractSuper() 
            {
                Debug.WriteLine("这是父类的构造方法");
            }
     
            public abstract void Init();
     
            public void Hello() 
            {
                Debug.WriteLine("这是父类的非抽象方法");
            }
        }
    }
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
     
    using System.Diagnostics;
     
    namespace TestAppAllHere
    {
        class TestAbstractSub:TestAbstractSuper
        {
            public TestAbstractSub() 
            {
                Debug.WriteLine("这是子类的构造方法");
            }
     
            public override void Init()
            {
                Debug.WriteLine("这是子类重写的方法");
            }
            
        }
    }
    
    TestAbstractSub sub = new TestAbstractSub();
    sub.Init();
    sub.Hello();
    
    这是父类的构造方法
    这是子类的构造方法
    这是子类重写的方法
    这是父类的非抽象方法
    
    二、virtual
    • 声明了virtual的方法无需去改动类的声明,他只在此方法上起到影响。
    • 只有virtual的方法可以被子类override。
    • 子类可以不override父类的virtual方法,这种情况下他就像普通的父类方法一样。

    小结:简单概括一下,virtual关键字就是告诉子类,此方法可以被override,但非强制。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
     
    using System.Diagnostics;
     
    namespace TestAppAllHere
    {
        class TestVirtualSuper
        {
            public TestVirtualSuper() 
            {
                Debug.WriteLine("这是父类的构造方法");
            }
            public virtual void Init() 
            {
                Debug.WriteLine("这是父类的虚拟方法");
            }
        }
    }
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
     
    using System.Diagnostics;
     
    namespace TestAppAllHere
    {
        class TestVirtualSub:TestVirtualSuper
        {
            public TestVirtualSub()
            {
                Debug.WriteLine("这是子类的构造方法");
            }
            //___________________没有重写这个虚拟方法也是可以照常运行的,会调用父类的虚拟方法_________________________
            //___________________重写了之后父类的虚拟方法不会运行,而是重写,当然可以用base.来调用父类的方法__________
            public override void Init()
            {
                //base.Init();
                Debug.WriteLine("这是子类的重写方法");
            }
     
        }
    }
    
    TestVirtualSub sub = new TestVirtualSub();
    sub.Init();
    
    这是父类的构造方法
    这是子类的构造方法
    这是子类的重写方法
    
    三、C#.NET里面抽象类和接口有什么区别

    如果单从具体代码来看,对这两个概念很容易模糊,甚至觉得接口就是多余的,因为单从具体功能来看,除多重继承外(C#,Java中),抽象类似乎完全能取代接口。但是,难道接口的存在是为了实现多重继承?当然不是。我认为,抽象类和接口的区别在于使用动机。使用抽象类是为了代码的复用,而使用接口的动机是为了实现多态性。所以,如果你在为某个地方该使用接口还是抽象类而犹豫不决时,那么可以想想你的动机是什么。

    看到有朋友对IPerson这个接口的质疑,我个人的理解是,IPerson这个接口该不该定义,关键看具体应用中是怎么个情况。如果我们的项目中有Women和Man,都继承Person,而且Women和Man绝大多数方法都相同,只有一个方法DoSomethingInWC()不同(例子比较粗俗,各位见谅),那么当然定义一个AbstractPerson抽象类比较合理,因为它可以把其他所有方法都包含进去,子类只定义DoSomethingInWC(),大大减少了重复代码量。

    但是,如果我们程序中的Women和Man两个类基本没有共同代码,而且有一个PersonHandle类需要实例化他们,并且不希望知道他们是男是女,而只需把他们当作人看待,并实现多态,那么定义成接口就有必要了。

    总而言之,接口与抽象类的区别主要在于使用的动机,而不在于其本身。而一个东西该定义成抽象类还是接口,要根据具体环境的上下文决定。

    再者,我认为接口和抽象类的另一个区别在于,抽象类和它的子类之间应该是一般和特殊的关系,而接口仅仅是它的子类应该实现的一组规则。(当然,有时也可能存在一般与特殊的关系,但我们使用接口的目的不在这里)如,交通工具定义成抽象类,汽车、飞机、轮船定义成子类,是可以接受的,因为汽车、飞机、轮船都是一种特殊的交通工具。再譬如Icomparable接口,它只是说,实现这个接口的类必须要可以进行比较,这是一条规则。如果Car这个类实现了Icomparable,只是说,我们的Car中有一个方法可以对两个Car的实例进行比较,可能是比哪辆车更贵,也可能比哪辆车更大,这都无所谓,但我们不能说“汽车是一种特殊的可以比较”,这在文法上都不通。

    接口和抽象类的概念不一样。接口是对动作的抽象,抽象类是对根源的抽象。抽象类表示的是,这个对象是什么。接口表示的是,这个对象能做什么。比如,男人,女人,这两个类(如果是类的话……),他们的抽象类是人。说明,他们都是人。人可以吃东西,狗也可以吃东西,你可以把“吃东西”定义成一个接口,然后让这些类去实现它。

    所以,在高级语言上,一个类只能继承一个类(抽象类)(正如人不可能同时是生物和非生物),但是可以实现多个接口(吃饭接口、走路接口)。

    四、sealed

    参考 C#中sealed关键字

    当对一个类应用 sealed 修饰符时,此修饰符会阻止其他类从该类继承。类似于Java中final关键字。

    相关文章

      网友评论

          本文标题:C# abstract virtual sealed

          本文链接:https://www.haomeiwen.com/subject/uoiuzltx.html