目录:

    • 一、虚方法的概念
    • 二、虚方法的特点
    • 三、虚方法的作用
    • 四、虚方法的声明
    • 五、虚方法的执行
    • 六、虚拟类的规则

一、虚方法的概念

在C#中,虚方法就是可以被子类重写的方法,如果子类重写了虚方法,则在运行时将运行重写的逻辑;如果子类没有重写虚方法,则在运行时将运行父类的逻辑。虚函数在编译期间是不被静态编译的,它的相对地址是不确定的,它会根据运行时期对象实例来动态判断要调用的函数,其中那个申明时定义的类叫申明类,那个执行时实例化的类叫实例类。虚方法是用virtual关键字声明的

A a = new B(); 其中A是申明类,B是实例类。

 

二、虚方法的特点

  1. 虚方法前不允许有static,abstract,或override修饰符(因为静态的方法和抽象方法不能重写)
  2. 虚方法不能是私有的(因为在子类中要进行重写),所以不能使用private修饰符
  3. 不能在声明虚方法的同时指定重写虚方法,因为重写方法只能重写基类的虚方法,也就是要提前在基类中声明虚方法,所以virtual关键字和override关键字不能同时使用。

三、虚方法的作用

  1. 允许派生类(即其子类)对父类进行扩展。
  2. 虚方法是多态特性的一种体现。
  3. 增加开发过程中的可维护性,条理清晰明了。

四、虚方法的声明

在父类中:

1
2
3
4
public virtual 返回类型 方法名()

{

    方法体;

}

在子类中:

1
2
3
4
5
public override 返回值类型 方法名()

{

    base.父类方法;

    方法体;

}

五、虚方法的执行

一般方法在编译时就静态地编译到了执行文件中,其相对地址在程序运行期间是不发生变化的,也就是写死了的!

虚函数在编译期间是不被静态编译的,它的相对地址是不确定的,它会根据运行时期对象实例来动态判断要调用的函数。

具体的检查流程如下:

  1. 当调用一个对象的方法时,系统会直接去检查这个对象申明定义的类,即申明类,看所调用的方法是否为虚方法。
  2. 如果不是虚函数,那么它就直接执行该函数。如果有virtual关键字,也就是一个虚方法,那么这个时候它就不会立刻执行该函数了,而是转去检查对象的实例类。
  3. 在这个实例类里,它会检查这个实例类的定义中是否有实现该虚方法(通过new关键字)或是否有重新实现该虚方法(通过override关键字),如果有,那么OK,它就不会再找了,而马上执行该实例类中的这个重新实现的方法。而如果没有的话,系统就会不停地往上找实例类的父类,并对父类重复刚才在实例类里的检查,直到找到第一个重载了该虚方法的父类为止,然后执行该父类里重载后的方法。

下面我们通过具体实例看看:

例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    class A

    {

        public virtual void Getreturn()

        {

            Console.WriteLine("我是A类的虚方法");

        }

    }

    class Program

    {

        static void Main(string[] args)

        {

            A a = new A();//定义一个a这个A类的对象,这个A就是a的申明类,实例化a对象,A是a的实例类

            a.Getreturn();

            Console.ReadLine();

        }

    }

过程:1.先检查申明类A 2.检查到是Getreturn是虚拟方法 3.转去检查实例类A,结果是它本身 4.执行实例类A中实现Getreturn的方法 5.输出结果我是A类的虚方法

例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    class A

    {

        public virtual void Getreturn()

        {

            Console.WriteLine("我是A类的虚方法");

        }

    }

    class B : A

    {

        public override void Getreturn() //重新实现了虚方法

        {

            Console.WriteLine("我是B类重写后的方法");

        }

    }

    class Program

    {

        static void Main(string[] args)

        {

            A a = new B();//定义一个a这个A类的对象,这个A就是a的申明类,实例化a对象,B是a的实例类

            a.Getreturn();

            Console.ReadLine();

        }

    }

过程:1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类B,有重写的方法 4.执行实例类B中的方法 5.输出结果我是B类重写后的方法

例3:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    class A

    {

        public virtual void Getreturn()

        {

            Console.WriteLine("我是A类的虚方法");

        }

    }

    class B : A

    {

        public override void Getreturn() //重新实现了虚方法

        {

            Console.WriteLine("我是B类重写后的方法");

        }

    }

    class C : B

    {

   

    }

    class Program

    {

        static void Main(string[] args)

        {

            A a = new C();//定义一个a这个A类的对象,这个A就是a的申明类,实例化a对象,C是a的实例类

            a.Getreturn();

            Console.ReadLine();

        }

    }

过程:1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类C,无重写的方法 4.转去检查类C的父类B,有重写的方法5.执行父类B中的Getreturn方法 6.输出结果我是B类重写后的方法

例4:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    class A

    {

        public virtual void Getreturn()

        {

            Console.WriteLine("我是A类的虚方法");

        }

    }

    class B : A

    {

        public new void Getreturn() //覆盖父类里的同名函数,而不是重新实现  

        {

            Console.WriteLine("我是B类New方法");

        }

    }

    class Program

    {

        static void Main(string[] args)

        {

            A a = new B();//定义一个a这个A类的对象,这个A就是a的申明类,实例化a对象,B是a的实例类

            a.Getreturn();

            Console.ReadLine();

        }

    }

过程:1.先检查申明类A 2.检查到是虚拟方法
3.转去检查实例类B,无重写的(这个地方要注意了,虽然B里有实现Getreturn(),但没有使用override关键字,所以不会被认为是重写)
4.转去检查类B的父类A,就是它本身 5.执行父类A中的Getreturn方法 6.输出结果我是A类的虚方法

例5:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    class A

    {

        public virtual void Getreturn()

        {

            Console.WriteLine("我是A类的虚方法");

        }

    }

    class B : A

    {

        public new void Getreturn() //覆盖父类里的同名函数,而不是重新实现  

        {

            Console.WriteLine("我是B类New方法");

        }

    }

    class Program

    {

        static void Main(string[] args)

        {

            B b = new B();//定义一个b这个B类的对象,这个B就是b的申明类,实例化b对象,B是b的实例类

            b.Getreturn();

            Console.ReadLine();

        }

    }

过程:1.先检查申明类B 2.检查到不是虚拟方法 3.执行B类里的Getreturn() 4.输出结果我是B类New方法

可以使用抽象方法重写基类中的虚方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    class A

    {

        public virtual void Getreturn()

        {

            Console.WriteLine("A类的虚方法");  

        }  

    }

    abstract class B : A    

    {

        public abstract override void Getreturn();//使用override修饰符,表示抽象重写了基类中该函数的实现

    }

    abstract class C : A

    {

        public abstract new void Getreturn();//使用new修饰符显式声明,表示隐藏了基类中该函数的实现

    }

密封类可以重写基类中的虚方法(基类中的虚方法将隐式的转化为非虚方法,但密封类本身不能再增加新的虚方法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    class A

    {

        public virtual void Getreturn()

        {

            Console.WriteLine("A类的虚方法");

        }

    }

    sealed class Program:A

    {

        public override void Getreturn()

        {

            Console.WriteLine("Program类重写后的方法");

        }

        static void Main(string[] args)

        {

            Program p = new Program();

            p.Getreturn();

            Console.ReadLine();

        }

    }

 虚方法和new

new关键用于隐藏父类的成员,所有可以用new关键字隐藏父类的虚拟方法。

abstract和虚拟方法

抽象方法是隐式的虚拟方法,所有抽象类的非抽象子类可以用new 和override关键来重写abstract 方法

【C#基础概念】虚方法virtual的更多相关文章

  1. Delphi之静态方法,虚方法virtual,动态dynamic,抽象abstract,消息

    Delphi之静态方法,虚方法virtual,动态dynamic,抽象abstract,消息 http://www.cnblogs.com/zhwx/archive/2012/08/28/266055 ...

  2. 虚方法(virtual)和抽象方法(abstract)的和接口(interface)的区别

    虚方法(virtual)和抽象方法(abstract)的区别 2017年06月15日 13:41:26 阅读数:65 注:本文转载自 http://www.cnblogs.com/michaelxu/ ...

  3. C#虚方法virtual详解

    转: http://www.cnblogs.com/jason_yjau/archive/2009/08/25/1553949.html C#虚方法virtual详解 在C++.Java等众多OOP语 ...

  4. 4.C#虚方法virtual详解

    C#虚方法virtual详解 在C++.Java等众多OOP语言里都可以看到virtual的身影,而C#作为一个完全面向对象的语言当然也不例外. 虚拟函数从C#的程序编译的角度来看,它和其它一般的函数 ...

  5. 抽象方法(abstract method) 和 虚方法 (virtual method), 重载(overload) 和 重写(override)的区别于联系

    1. 抽象方法 (abstract method) 在抽象类中,可以存在没有实现的方法,只是该方法必须声明为abstract抽象方法. 在继承此抽象类的类中,通过给方法加上override关键字来实现 ...

  6. 虚方法virtual详解

    虚方法virtual详解   从C#的程序编译的角度来看,它和其它一般的函数有什么区别呢?一般函数在编译时就静态地编译到了执行文件中,其相对地址在程序运行期间是不发生变化的,也就是写死了的!而虚函数在 ...

  7. 虚方法(virtual)

    虚方法(virtual) Virtual 关键字用于修饰方法.属性.索引器或事件声明,并且允许在派生类中重写这些对象. 看一段代码: using System ; class A { public v ...

  8. 虚方法(virtual)\抽象方法(abstract)\接口(interface)的区别

    转自:https://www.cnblogs.com/fantaohaoyou/p/9402657.html 虚方法和抽象方法都可以供派生类重写,它们之间有什么区别呢? 1. 虚方法必须有实现部分,抽 ...

  9. [转]虚方法(virtual)和抽象方法(abstract)的区别

    虚方法和抽象方法都可以供派生类重写,它们之间有什么区别呢? 1. 虚方法必须有实现部分,抽象方法没有提供实现部分,抽象方法是一种强制派生类覆盖的方法,否则派生类将不能被实例化.如: //抽象方法pub ...

随机推荐

  1. DEEP LEARNING WITH PYTORCH: A 60 MINUTE BLITZ | TORCH.AUTOGRAD

    torch.autograd 是PyTorch的自动微分引擎,用以推动神经网络训练.在本节,你将会对autograd如何帮助神经网络训练的概念有所理解. 背景 神经网络(NNs)是在输入数据上执行的嵌 ...

  2. 集合框架-HashSet存储自定义对象

    1 package cn.itcast.p4.hashset.test; 2 3 import java.util.HashSet; 4 import java.util.Iterator; 5 6 ...

  3. Web播放器

    web视频播放器的使用及遇到的问题记录 TcPlayer播放器(腾讯Web超级播放器) https://cloud.tencent.com/document/product/881/20207 Ste ...

  4. 源码分析axios(1)~源码分析、模拟axios的创建

    ■ 查看源码发现,起初axios[instance=bind(Axios.prototype.request, context);]是一个函数, 但后续[ utils.extend(instance, ...

  5. 人口信息普查系统-JavaWeb-一

    建民说要期中考试了,我赶紧翻阅了去年的考试题目,去年的试题是要求做一个人口普查系统.我就试着做了一下,今天主要和大家分享题目要求. 其中考试确实有些难度,用到了许多没有接触过的知识,比如JavaScr ...

  6. 右键没有word?excel?ppt?注解表该改改啦

    ✿[office 2019]office2010版本以上的都可以(例如:office 2010.office 2016.office 2019) 一.快速方法解决右键没有word: 在电脑桌面右键一个 ...

  7. python基础详解

    python基础部分 python基础一 python基础二 Python最详细,最深入的代码块小数据池剖析 深浅copy python文件操作 python函数部分 python函数初识 pytho ...

  8. SQL 中进行递归

    很多时候,我们做Tree的时候会用到递归.但是一般都是从数据库中拿到数据然后再程序中进行递归.昨天一个巧合,一位同事给我看了数据库中的递归,乍一看还不太明白. 表结构是这样的 CREATE TABLE ...

  9. HUWEI交换机如何判断环路故障

    定义 以太网交换网络中为了提高网络可靠性,通常会采用冗余设备和冗余链路,然而现网中由于组网调整.配置修改.升级割接等原因,经常会造成数据或协议报文环形转发,不可避免的形成环路.如图1所示,三台设备两两 ...

  10. 「BalkanOI 2018 Day1」Election

    「BalkanOI 2018 Day1」Election 记C为1,T为-1,\(sum[i]\)为\(i\)点的前缀和. 对于询问\([l,r]\),分两步计算答案. 要求所有点的\(sum[i]- ...