C# virtual方法的用法



转载自博客园

http://www.cnblogs.com/jiajiayuan/archive/2011/09/14/2176015.html


若一个实例方法声明前带有virtual关键字,那么这个方法就是虚方法。
虚方法与非虚方法的最大不同是,虚方法的实现可以由派生类所取代这种取代是通过方法的重写实现的(以后再讲)
虚方法的特点:
虚方法前不允许有static,abstract,或override修饰符
虚方法不能是私有的,因此不能使用private修饰符
虚方法的执行:
我们知道一般函数在编译时就静态地编译到了执行文件中,其相对地址在程序运行期间是不发生变化的,
而虚函数在编译期间是不被静态编译的,它的相对地址是
不确定的,它会根据运行时期对象实例来动态判断要调用的函数

其中那个申明时定义的类叫申明类,那个执行时实例化的类叫实例类。
如:A a =new B(); 其中A是申明类,B是实例类。
1.当调用一个对象的函数时,系统会直接去检查这个对象申明定义的类,即申明类,看所调用的函数是否为虚函数;

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

例1:

复制代码
    class A
    {
        public virtual void Sum()
        {
            Console.WriteLine("I am A Class,I am virtual sum().");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
             A a=new A();   // 定义一个a这个A类的对象.这个A就是a的申明类,实例化a对象,A是a的实例类   
             a.Sum();
             Console.Read();
        }
    }
复制代码

 执行a.Sum:
1.先检查申明类A 2.检查到是sum是虚拟方法 3.转去检查实例类A,结果是题本身
4.执行实例类A中实现Sum的方法 5.输出结果 I am A Class,I am virtual sum().
例2:

复制代码
class A
    {
        public virtual void Sum()
        {
            Console.WriteLine("I am A Class,I am virtual sum().");
        }
    }
    class B : A    
    {
        public override void Sum() // 重新实现了虚函数   
        {
            Console.WriteLine("I am B Class,I am override sum().");
        }  

    }
    class Program
    {
        static void Main(string[] args)
        {
             A a=new B();  // 定义一个a这个A类的对象.这个A就是a的申明类,实例化a对象,B是a的实例类              
             a.Sum();
             Console.Read();
        }
    }
复制代码

执行a.Sum:
1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类B,有重写的方法 4.执行实例类B中的方法 5.输出结果 I am B Class,I am override sum().
例3:

复制代码
    class A
    {
        public virtual void Sum()
        {
            Console.WriteLine("I am A Class,I am virtual sum().");
        }
    }
    class B : A    
    {
        public override void Sum() // 重新实现了虚函数   
        {
            Console.WriteLine("I am B Class,I am override sum().");
        }  

    }
    class C : B
    {

    }
    class Program
    {
        static void Main(string[] args)
        {
             A a=new C();// 定义一个a这个A类的对象.这个A就是a的申明类,实例化a对象,C是a的实例类              
             a.Sum();
             Console.Read();
        }
    }
复制代码

执行a.Sum:
1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类C,无重写的方法 4.转去检查类C的父类B,有重写的方法
5.执行父类B中的Sum方法 6.输出结果 I am B Class,I am override sum(). 
例4:

复制代码
   class A
    {
        public virtual void Sum()
        {
            Console.WriteLine("I am A Class,I am virtual sum().");
        }
    }
    class B : A    
    {
        public new void Sum() //覆盖父类里的同名函数,而不是重新实现  
        {
            Console.WriteLine("I am B Class,I am new sum().");
        }  

    }
    class Program
    {
        static void Main(string[] args)
        {
             A a=new B();
             a.Sum();
             Console.Read();
        }
    }
复制代码

执行a.Sum:
1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类B,无重写的(这个地方要注意了,虽然B里有实现Sum(),但没有使用override关键字,所以不会被认为是重写) 4.转去检查类B的父类A,就为本身 5.执行父类A中的Sum方法 6.输出结果 I am A Class,I am virtual sum(). 
那么如果在例4里,申明的是类B呢?

复制代码
    class A
    {
        public virtual void Sum()
        {
            Console.WriteLine("I am A Class,I am virtual sum().");
        }
    }
    class B : A    
    {
        public new void Sum() //覆盖父类里的同名函数,而不是重新实现  
        {
            Console.WriteLine("I am B Class,I am new sum().");
        }  

    }
    class Program
    {
        static void Main(string[] args)
        {
             B b=new B();
             b.Sum();
             Console.Read();
        }
    }
复制代码

执行B类里的Sum(),输出结果I am B Class,I am new sum().
可以使用抽象函数重写基类中的虚函数吗?
答案是可以的。

复制代码
    class A
    {
        public virtual void PrintFriends()
        {
            Console.WriteLine("A.PrintFriends()");   
        }  
    }
    abstract class B : A    
    {
        public abstract override void PrintFriends();   //使用override 修饰符,表示抽象重写了基类中该函数的实现
    }
    abstract class C : A
    {
        public abstract new void PrintFriends();        //使用 new 修饰符显式声明,表示隐藏了基类中该函数的实现
    }
复制代码

密封类可以有虚函数吗?
可以,基类中的虚函数将隐式的转化为非虚函数,但密封类本身不能再增加新的虚函数

复制代码
    class A
    {
        public virtual void Fun()
        {
            Console.WriteLine("I am A.");
        }
    }
    sealed class Program:A
    {
        public override void Fun()
        {
            Console.WriteLine("I am B.");
        }
        static void Main(string[] args)
        {
            Program p = new Program();
            p.Fun();
            Console.Read();
        }
    }

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,并在文章页面明显位置以超链接形式注明出处,否则保留追究法律责任的权利。
复制代码
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C#virtual关键字用于修饰基类的方法、属性、索引器或事件声明。被virtual修饰的方法、属性、索引器或事件是可以在派生类重写的,也就是可以进行修改。虚方法是指被virtual关键字修饰的基类实例方法,需要在派生类进行重写和修改。重写方法需要使用override关键字声明,表示覆盖基类的方法。派生类重写的方法的签名和返回值类型必须与基类的相同。如果基类的方法virtual修饰,但派生类在重写时没有使用override关键字修饰,会发出警告。如果派生类没有重写基类的方法,只是继承了该方法,那么调用派生类的这个方法时,输出的结果肯定是基类的。virtual修饰符不能与static、abstract、private和override关键字一起使用。在C#,虚拟函数是在运行时根据对象实例动态判断要调用的函数,而一般函数在编译时就静态地编译到执行文件。调用一个对象的函数时,系统会检查该对象申明定义的类,看所调用的函数是否为虚函数。如果是虚函数,系统会根据对象的实例类来判断要调用的函数,如果实例类有重新实现该虚函数的方法,则执行该方法,否则会沿着父类链继续寻找重载了该虚函数的父类,并执行重载后的函数。 #### 引用[.reference_title] - *1* *2* [C#关键字——virtual浅见](https://blog.csdn.net/abraham_ly/article/details/106721488)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [C#方法virtual详解](https://blog.csdn.net/m0_65636467/article/details/128797283)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值