首页 > 编程语言 >C# virtual 关键字

C# virtual 关键字

时间:2024-06-09 20:57:43浏览次数:11  
标签:Console C# Work Derived virtual 关键字 WriteLine new public

image.png

virtual 使用

c#的方法,默认为非虚方法,如果一个方法被声明为 virtual (虚方法),则继承该方法的任何类都可以实现它自己的版本。

public class BaseEngineer
{
    public virtual void Work()
    {
        Console.WriteLine("BaseEngineer.Work");
    }
}

virtual 方法可以通过 Overridenew 关键字来进行版本控制、重写.

Override 关键字

Override 用来重写基类的虚方法。如下例子中,override 关键字可以确保派生类 JuniorEngineer / SeniorEngineer 的任何对象将使用 work 的派生类版本,同时又可以通过 base 关键字访问基类的版本。

public class JuniorEngineer : BaseEngineer
{
    public override void Work()
    {
        base.Work();
        Console.WriteLine("=>JuniorEngineer.Work");
    }
}
public class SeniorEngineer : BaseEngineer
{
    public override void Work()
    {
        base.Work();
        Console.WriteLine("=>SeniorEngineer.Work");
    }
}

var juniorEngineer = new JuniorEngineer();
juniorEngineer.Work();

var seniorEngineer = new SeniorEngineer();
seniorEngineer.Work();
----------------------Output---------------------------
BaseEngineer.Work
=>JuniorEngineer.Work
BaseEngineer.Work
=>SeniorEngineer.Work

New 关键字

派生类的方法前面带有 new 关键字,则该方法被定义为独立于基类中的方法,用 new 关键字可以隐藏基类中的虚方法。

假如派生类中的方法前面没有 new / override 关键字,那么编译期会发出 Warning,并将该方法作为有 new 关键字去执行。

public class SuperEngineer : BaseEngineer
{
    public new void Work()
    {
        base.Work();
        Console.WriteLine("=>Eat a bug!");
        Console.WriteLine("=>Create lots of bugs!");
    }
}

var superEngineer = new SuperEngineer();
superEngineer.Work();
----------------------Output---------------------------
BaseEngineer.Work
=>Eat a bug!
=>Create lots of bugs!

何时使用 Override / New 关键字?

从上面可以看到,无论使用 Override / New 中哪一个,派生类的实例似乎都可以重新定义方法内容,也可以调用base的方法,那么为何要有2个关键字呢?

上面的例子,我们稍微改动一点,所有 override / new 的实现中,都不再调用 base 的虚方法,并通过基类访问派生类实例:

public class JuniorEngineer : BaseEngineer
{
    public override void Work()
    {
        Console.WriteLine("=>JuniorEngineer.Work");
    }
}
public class SeniorEngineer : BaseEngineer
{
    public override void Work()
    {
        Console.WriteLine("=>SeniorEngineer.Work");
    }
}
public class SuperEngineer : BaseEngineer
{
    public new void Work()
    {
        Console.WriteLine("=>Eat a bug!");
        Console.WriteLine("=>Create lots of bugs!");
    }
}

var enginners = new List<BaseEngineer>
{
    juniorEngineer,
    seniorEngineer,
    superEngineer
};

foreach (var enginner in enginners)
{
    enginner.Work();
}

--------------Output----------------------
=>JuniorEngineer.Work
=>SeniorEngineer.Work
BaseEngineer.Work

Junior / Senior 都如期工作,调用了派生类中的方法,而最后的 SuperEngineer 并没有执行派生类的方法,而是执行了基类的虚方法。

因为数组的类型为 BaseEngine,且派生类 SuperEngineer 使用了 new 关键字重新定义方法,因此最终执行的是基类虚方法。

不要在构造函数里调用虚函数

这一条是引自《Effective c#》,在构建对象的过程中调用虚方法会使程序表现出奇怪的行为,因为这个时候对象并没有完全构造好。将书中的例子改的更为详尽一些:

public class VirtualB
{
    protected VirtualB()
    {
        Console.WriteLine("VritualB constructor start");
        VFunc();
        Console.WriteLine("VritualB constructor end");
    }

    protected virtual void VFunc()
    {
        Console.WriteLine("VirtualB.VFunc");
    }
}
public class Derived : VirtualB
{
    private readonly string msg = "Set by initializer";

    public Derived(string msg)
    {
        Console.WriteLine("Derived constructor start");
        this.msg = msg;
        VFunc();
        Console.WriteLine("Derived constructor end");
    }

    protected override void VFunc()
    {
        Console.WriteLine($"Derived: {msg}");
    }
}

var d = new Derived("Constructed in main");

----------------Output---------------------------
VritualB constructor start
Derived: Set by initializer
VritualB constructor end
Derived constructor start
Derived: Constructed in main
Derived constructor end

基类的构造函数调用了一个定义在本类中的虚函数,于是派生类实例在运行时调用的就是派生类的版本,即 Derived 的派生版本。

C# 在进入构造函数体之前,已经把该对象的所有成员变量初始化好了,即开发者声明每一个成员变量时写的所有初始化语句都得到了执行。

整个流程如下:

  1. msg 首先通过初始化语句赋值为 "Set by initializer"
  2. 开始执行构造函数,先执行 base 构造函数
    • base 构造函数调用派生类中的 VFunc 中的方法输出 "Derived: Set by initializer"
  3. 执行派生类 Derived 构造函数
    • msg 通过构造函数入参赋值为 "Constructed in main"
    • 再次调用 VFunc

可以看到,构造函数中调用虚方法,可能会导致程序结果不是我们所期望的,除非你清晰理解c#语言规范,否则这样会令程序可读性降低,甚至引起数据混乱。

标签:Console,C#,Work,Derived,virtual,关键字,WriteLine,new,public
From: https://www.cnblogs.com/wenxin1225/p/18239979

相关文章

  • Misc( 15 )
    [UTCTF2020]FileCarving下载文件,是这样的一张图片先是拖入010中,没有找到任何有价值的信息,用binwalk打开,分离得到了一个压缩包拖入010中,搜索flagflag{2Hºfbe9adc2H‰EÀH‰UÈH¸ad89c71dHºa48cabe9H‰EÐH‰UØH¸0a121c0}复制出来删除大写和非法字符,拿到flag:flag......
  • BUUCTF-Misc(131-140)
    [ACTF新生赛2020]剑龙打开pwd.txt发现是颜文字然后打开随波逐流,AAencode颜文字解密得到welcom3!看一下这个图片的详细信息,发现然后用颜文字结出来的那个密码,去steghide解密U2FsdGVkX1/7KeHVl5984OsGUVSanPfPednHpK9lKvp0kdrxO4Tj/Q==又是U2f然后这次我还以为是AES加密......
  • ReentrantLock类
    ReentrantLock与synchronized相比有以下特点可中断可以设置为公平锁支持多个条件变量与sychronized一样的支持可重入锁可打断锁(避免死锁):使用lockInterruptibly()方法publicclassTestReentrant{privatestaticReentrantLocklock=newReentrantLock();......
  • ABC 315F Shortcuts
    题意有N个点,你从第一个点出发,要按顺序经过所有的点,最终抵达第N个点。在这个过程中你可以跳过一些点,但如果你跳过了C个点,那么你必须要接受pow(2,C-1)的惩罚。设s为你走过的距离加上你的惩罚,请求出最小化s。题解显然考虑dp,设计dp[i][j]为到达第i个点,中途跳过了j个点需要的路程。......
  • 【C语言从入门到入土】第四章数组
    第四章数组———————-数组的引入你所有的压力,都是因为你太想要了,你所有的痛苦,都是因为你太较真了。有些事不能尽你意,就是在提醒你改转弯了。如果事事都如意,那就不叫生活了,珍惜所有不期而遇,看淡所有的不辞而别。文章目录第四章数组4.1如何定义一个数组1.相同......
  • (PAT乙级刷题)擅长C
    题目: 输入样式..C...C.C.C...CCCCCCC...CC...CC...CCCCC.C...CC...CCCCC.C...CC...CCCCC..CCC.C...CC....C....C....C...C.CCC.CCCC.C...CC...CC...CC...CC...CCCCC.CCCCCC....C....CCCC.C....C....CCCCCCCCCCC....C....CCCC.C..........
  • 计算机组成原理-cache详解
    一、Cache的概念和原理1、cache原理2、cache性能分析一道例题3、cache和主存数据交换的单位每次访问到的主存块会立即放入cache中小结二、cache和主存之间的映射关系全相联映射全相联访存过程直接映射组相联映射小结三、cache替换算法在直接映射中,每......
  • 使用 ECharts 绘制3D饼图,立体效果华丽渲染!
    ✈️✈️✈️目录使用ECharts绘制3D饼图首先了解3D饼图的构成准备工作数据定义绘制一个三维饼图合并配置并初始化图表实践结语使用ECharts绘制3D饼图在数据可视化中,饼图是表达数据占比信息的常见方式。ECharts作为一个强大的数据可视化库,除了标准的二维饼图,也支持更......
  • ChatGPT-4o提示词的九大酷炫用法,你知道几个?
    ChatGPT-4o提示词的九大酷炫用法,你知道几个?......
  • Ten Tips for Smarter Google Searches (十个更聪明使用 Google 搜索的技巧)
    TenTipsforSmarterGoogleSearches十个更聪明使用Google搜索的技巧 Date:Dec1,2006Articleisprovidedcourtesyof Que.Returntothearticle MostpeopleuseGoogleinaveryinefficientandoftenineffectivemanner.Ifallyoudoisenterafew......