【问题标题】:multi level inheritance in C# without 'virtual' keywordC# 中没有“virtual”关键字的多级继承
【发布时间】:2019-05-23 04:27:37
【问题描述】:

我是 C# 新手,只是一个关于多级继承的问题 假设我们有以下类:

Class Employee
{
   public virtual void CalculateBonus() {
      ...
   }
}

class SalesPerson : Employee 
{
    public override void CalculateBonus() {
      ...
   }
}

假设我们有另一个派生自 SalesPerson 的类

class PTSalesPerson : SalesPerson
{
   public override void CalculateBonus() {
      ...
   }
}

所以我的问题很简单,基类中的 virtual 关键字需要被其子类覆盖。应用相同的逻辑,虚拟关键字也应该应用在 SalesPerson 类中:

class SalesPerson : Employee 
{
   public virtual override void CalculateBonus() {
     ... //compiler error
   }
}

以便 PTSalesPerson 可以覆盖其父方法。 那么是否意味着“虚拟”关键字只需要出现在 1 级基类中?还是覆盖 = 覆盖 + 虚拟?

【问题讨论】:

  • 您是否只是尝试了两种方式,看看会发生什么?嗯,是的,你做了,你得到了一个编译器错误。你为什么要问这个问题?
  • 一旦一个方法在一个类中被声明为virtual,它也将在它的所有子类中隐式地是virtual,而不需要重用关键字。
  • PTSalesPerson 已经可以在没有任何帮助的情况下覆盖 CalculateBonus。这听起来很像您需要一种新方法,而不是CalculateBonus。这个新方法仍然可以调用CalculateBonus,如果合适的话,封装是另一个容易被忽视的oop 技术。调用这个新方法并不一定简单,调用者必须知道一个 Employee 对象至少是一个 SalesPerson。 is 运算符可以帮助解决这个问题。

标签: c# oop


【解决方案1】:

您不能将 覆盖 方法标记为 virtual,因为它在定义上已经是虚拟的

virtual (C# Reference)

备注

当调用虚方法时,对象的运行时类型为 检查覆盖成员。最重要的成员 派生类被调用,它可能是原始成员,如果没有 派生类已经覆盖了成员。

默认情况下,方法是非虚拟的。您不能覆盖非虚拟 方法。

您不能将 virtual 修饰符与 static、abstract、private 或 override 修饰符一起使用。


如果你这样做,你会得到一个令人讨厌的编译时错误

Compiler Error CS0113

标记为覆盖的成员“函数”不能标记为新的或 虚拟的

用new和override标记方法是互斥的 关键字。


为了回答潜在的问题,您将需要覆盖的最低级别标记为virtual,然后任何派生类都可以override

【讨论】:

  • 这个答案只缺少一件事:根据定义,覆盖成员是虚拟的,因此将其标记为覆盖和虚拟是荒谬的。
【解决方案2】:

VIRTUAL 关键字意味着任何子级类都可以覆盖给定的函数。

因此,如果 NONE 子级别的类有函数的覆盖声明,它们都将仍然具有该函数,它只会转到最顶层的员工类。

例如,如果您只对 PTSalesPerson 类进行了专门的覆盖,那么只有该类将具有不同的功能...... Employee 和 SalesPerson 仍将在函数/方法的“员工”级别声明上运行。

这对你有帮助吗?

一旦任何方法在其父层次结构中被声明为虚拟,任何子级总是可能从其父级覆盖,无论级别如何。而且,假设您有一个层次结构级别

Class1
  Class2 : Class1
    Class3 : Class2
      Class4 : Class3

并且您在 Class3 声明了一个覆盖... Class4 的实例将基于 IT 的父级操作,它是 Class3 的方法调用实现,而不是 Class1 的声明。

现在,如果你想做一个组合,你总是可以调用基础方法,然后做更多。

例如:

Class Employee
{
   public decimal MyBonus = 0.0m;
   public virtual void CalculateBonus() 
   {
      MyBonus = MySales * .13m;
   }
}

class SalesPerson : Employee 
{
}

class PTSalesPerson : SalesPerson
{
   public override void CalculateBonus() 
   {
      // go do the NORMAL Calculation at the EMPLOYEE Level
      base.CalculateBonus();
      // Now continue from that... As Part-Time sales person,
      // they get 1/4 of that rate.  So take whatever the result
      // WAS and multiply by .25
      MyBonus = MyBonus * .25m;
   }
}

关于调用方法链的说明

根据您的评论/问题,PTSalesPerson 将覆盖的方法将是Employees,因为这是链上的下一个声明方法...对于测试,请创建您自己的类,如上所示,然后执行 MessageBox.Show("一些东西”),看看每个人会发生什么。如果 SalesPerson 类有一个声明的方法,那么 THAT 将是一个被覆盖的方法,但也是被调用的“base.CalculateBonus”。

想想“基地”。作为家庭等级。你是你父母的孩子……你祖父母的孙子。所以你的“基地”。将是您的直接父母。

关于继承的补充说明

我没有透露的一个警告(感谢 Servy)是高级类声明,其中一个类被标记为 SEALED。密封类基本上锁定了类,因此不能对它进行进一步的派生类。这适用于整个类...属性、方法、功能等。

【讨论】:

  • 那么 PTSalesPerson 重写的方法是什么? SalesPerson 的 CalculateBonus() 还是 Employee .CalculateBonus()?
  • @slowjams,在我的答案底部添加了说明,请查看
  • “VIRTUAL 关键字意味着任何子级类都可以覆盖给定的函数。”这不是真的。虚拟方法也可以被密封,防止它被覆盖。
  • @Servy,是的,我同意,但我们从一个刚刚学习什么是虚拟 vs 覆盖的人开始,投入密封将进入一个新的 oohhhhhh 时刻。像任何东西一样。如果你有太多的东西扔给你,你只能吸收这么多,你工作,你学习,你变得更好并扩大学习。
  • 某人对该主题知之甚少,因此教他们准确的信息,而不是给他们完全错误的定义,这让他们更加重要。知识渊博的人可以阅读您的陈述,而不会感到困惑或偏离轨道,因为他们知道这不是真的,但是不了解的人只会因被教导错误的东西而受到严重伤害,并且将迫使他们在未来的某个时候不得不忘记你告诉他们的内容。
猜你喜欢
  • 2018-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-25
  • 1970-01-01
  • 2020-11-07
  • 1970-01-01
相关资源
最近更新 更多