关于覆盖规则C#的混淆

时间:2013-12-21 09:48:30

标签: c# oop virtual-functions method-overriding sealed

关于方法覆盖和OOP原则的有效性,我有一点混乱。 我知道关于密封,阴影,覆盖,虚拟等的一切,但我遇到了一个场景,这让我很困惑。假设我有:

class classA
{

    public virtual void sayhello()

      {
        Console.WriteLine("hello I'm A");
    }

};

class classB :classA
{
    public override void sayhello()
    {
        Console.WriteLine("hello I'm B");
    }

};
class Program
{
    static void Main(string[] args)
    {

        classB a = new classB();
        a.sayhello();
    }
}

根据我目前研究的所有内容,可以使用覆盖关键字覆盖声明为虚拟抽象(在抽象类中)的方法在儿童班。根据这个,上面的代码工作完美。 当我删除虚拟关键字,然后尝试使用覆盖关键字覆盖该方法时,编译器会将错误视为:

无法覆盖继承的成员'inheritence.classA.sayhello()',因为它未标记为虚拟,抽象或覆盖

然后我从子类中删除了覆盖关键字,并将实现提供为:

class classB :classA
{
    public void sayhello()
    {
        Console.WriteLine("hello I'm B");
    }

};

在这种情况下,该方法可以被覆盖。我能够覆盖不是虚拟或抽象的方法。所以,我的问题是:

1。它是否违反了OOP原则?因为我能够覆盖在父级中未标记为虚拟的方法。

2. 为什么我允许以这种方式覆盖方法?哪个甚至没有标记为虚拟

3。 classA 方法中删除虚拟关键字,它让我感觉密封方法< em> classA ,当我试图在 classB 中覆盖该方法时。 (正如我之前提到的编译器错误)。如果我删除虚拟,以便子类可能无法覆盖它,那么为什么子类会巧妙地覆盖它,删除其覆盖关键字?只有这种情况,密封关键字是专为?

设计的

5 个答案:

答案 0 :(得分:3)

我想告诉你,你隐藏了未被覆盖的父子方法 还有一件事你可能没有注意到这样做是看警告,因为在警告部分会明确提到,

  

警告'行号''classB .sayhello'隐藏了继承的成员'classA.sayhello'。使用新的   如果隐藏是关键字的关键字。

你的问题,

  

它是否违反了OOP原则?因为我能够覆盖在父级中未标记为虚拟的方法。

因为你隐藏了基类方法,所以它肯定没有违反OOP原则。

  

为什么我允许以这种方式覆盖方法?哪个甚至没有标记为虚拟?

因为C#不仅支持覆盖,还支持方法隐藏,并且必须使用new关键字声明隐藏方法。有关详细信息,请参阅dotnet_polymorphismoverriding-vs-method-hiding

  

仅此情况,密封关键字是专为?

设计的

来自MSDN sealed sealed关键字旨在阻止类的派生并否定虚拟成员的虚拟方面。

  • 当应用于类时,sealed修饰符会阻止其他类继承它。
  • 密封修饰符只能应用于覆盖基类中的虚拟方法或属性的方法或属性。这可以防止进一步覆盖特定的虚拟方法或属性,但它永远不会停止method-hiding 。阅读Non-overridable method了解更多信息

答案 1 :(得分:1)

  
      
  1. 它是否违反了OOP原则?因为我能够覆盖在父级中未标记为虚拟的方法。
  2.   

您没有override隐藏父方法的父method

所以你永远不能从子类对象访问父方法,因为你的子类hiddenmethod sayhello()

  

2.为什么我允许以这种方式覆盖方法?哪个甚至没有标记为虚拟?

因为您可以使用子实现隐藏父方法。

答案 2 :(得分:1)

我认为这来自C ++实现,它使用切片(What is object slicing?)。

虽然C#主要类似于Java,但在某些情况下(这个和值类型的存在)它遵循C ++方式。

之后的原因是,由于您的代码从sayhello变量调用方法A,程序员期望执行A.sayhello的逻辑。它不会破坏OOP原则,因为您正在执行A.sayhello实现(因此它必须与A.sayhello合同匹配)。

与Java不同的不是OOP而不是OOP,但是Java使用late binding(实际执行的方法是在运行时基于a实际实例决定的)而C#使用{{1 (除非方法是虚拟的,否则该方法在编译时确定)。

我个人更喜欢后期绑定,而从OOP的角度来看,C#方法是正确的,我发现通常应该使用更专业的方法。

答案 3 :(得分:1)

嗯,最后这很简单:

  1. 覆盖虚拟方法时,具体方法在运行时解析
  2. 使用new关键字(或完全废弃)时,您将根据代码中提供的类型信息在编译时执行静态替换操作
  3. 这是完全不同的两件事。

答案 4 :(得分:1)

你所做的是方法隐藏(正如其他人已经解释过的那样)。

如果你真的想这样做,你应该在方法定义中添加新关键字以使警告消失,并作为文档。因此,查看代码的其他开发人员知道您是故意这样做的。