惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Proofpoint News Feed
F
Full Disclosure
小众软件
小众软件
V
V2EX
月光博客
月光博客
人人都是产品经理
人人都是产品经理
有赞技术团队
有赞技术团队
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 司徒正美
M
MIT News - Artificial intelligence
Last Week in AI
Last Week in AI
The Register - Security
The Register - Security
T
Tailwind CSS Blog
Recorded Future
Recorded Future
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
aimingoo的专栏
aimingoo的专栏
Apple Machine Learning Research
Apple Machine Learning Research
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
阮一峰的网络日志
阮一峰的网络日志
B
Blog RSS Feed
IT之家
IT之家
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
F
Fortinet All Blogs
C
Check Point Blog
云风的 BLOG
云风的 BLOG
T
The Blog of Author Tim Ferriss
雷峰网
雷峰网
GbyAI
GbyAI
Microsoft Azure Blog
Microsoft Azure Blog
Hugging Face - Blog
Hugging Face - Blog
S
SegmentFault 最新的问题
V
Visual Studio Blog
J
Java Code Geeks
Y
Y Combinator Blog
A
About on SuperTechFans
Blog — PlanetScale
Blog — PlanetScale
美团技术团队
Vercel News
Vercel News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Stack Overflow Blog
Stack Overflow Blog
I
InfoQ
H
Help Net Security
MongoDB | Blog
MongoDB | Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Engineering at Meta
Engineering at Meta
Martin Fowler
Martin Fowler
The Cloudflare Blog
博客园 - 三生石上(FineUI控件)
D
Docker
The GitHub Blog
The GitHub Blog

博客园 - 寒山潜龙

『性能』List 和 HashSet 查找性能比较 (任何数据量的检索 从此只用 HashSet ) 人脸识别算法总结 神解释:UART、I2C、SPI、1-wire四大通信接口 解决github不显示图片的问题 树莓派SD卡容量扩展的方法 树莓派安装opencv调用cv2时提示 ModuleNotFoundError: NO module named 'cv2’的解决方法 在数莓派32位系统中安装opencv 4.5.5 树莓派官方32位和64位系统换源 linux系统压缩备份 Linux 解决 hosts 文件无法修改: ‘readonly‘ option is set (add ! to override) Paddle Lite——报错解决:基于Paddle Lite Demo运行run.sh编译报错无法运行 Debian系统安装opencv github 打不开一招搞定! - 寒山潜龙 树莓派4B安装 百度飞桨paddlelite 做视频检测 (一、环境安装) 今天有个朋友问我抽象方法和接口的区别,为了解释清楚这个事情,我在网上看到一篇文章讲的非常好给大家分享一下,也感谢原作者的付出 SQL2005四个排名函数(row_number、rank、dense_rank和ntile)的比较 Redis 集群方案 Android SDK Manager国内更新代理 AndroidDevTools简介 The status code returned from the server was: 500
C#之虚函数 非常清晰全面的讲解
寒山潜龙 · 2020-04-30 · via 博客园 - 寒山潜龙

原文地址:https://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关键字)的方法,
如果有,它就不会再找了,而是马上执行该实例类中实现的虚函数的方法。而如果没有的话,系统就会不停地往上找实例类的父类,
并对父类重复刚才在实例类里的检查,直到找到第一个重载了该虚函数的父类为止,然后执行该父类里重载后的函数。

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();
        }
    }
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();
        }
    }
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();
        }
    }
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();
        }
    }
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();
        }
    }
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();
        }
    }