关于方法覆盖和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 中覆盖该方法时。 (正如我之前提到的编译器错误)。如果我删除虚拟,以便子类可能无法覆盖它,那么为什么子类会巧妙地覆盖它,删除其覆盖关键字?只有这种情况,密封关键字是专为?
设计的答案 0 :(得分:3)
我想告诉你,你隐藏了未被覆盖的父子方法 还有一件事你可能没有注意到这样做是看警告,因为在警告部分会明确提到,
警告'行号'
'classB .sayhello'
隐藏了继承的成员'classA.sayhello'
。使用新的 如果隐藏是关键字的关键字。
你的问题,
它是否违反了OOP原则?因为我能够覆盖在父级中未标记为虚拟的方法。
因为你隐藏了基类方法,所以它肯定没有违反OOP原则。
为什么我允许以这种方式覆盖方法?哪个甚至没有标记为虚拟?
因为C#不仅支持覆盖,还支持方法隐藏,并且必须使用new
关键字声明隐藏方法。有关详细信息,请参阅dotnet_polymorphism和overriding-vs-method-hiding
仅此情况,密封关键字是专为?
设计的
来自MSDN sealed sealed
关键字旨在阻止类的派生并否定虚拟成员的虚拟方面。
method-hiding
。阅读Non-overridable method了解更多信息答案 1 :(得分:1)
- 它是否违反了OOP原则?因为我能够覆盖在父级中未标记为虚拟的方法。
醇>
您没有override
隐藏父方法的父method
。
所以你永远不能从子类对象访问父方法,因为你的子类hidden
是method 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)
嗯,最后这很简单:
new
关键字(或完全废弃)时,您将根据代码中提供的类型信息在编译时执行静态替换操作。 这是完全不同的两件事。
答案 4 :(得分:1)
你所做的是方法隐藏(正如其他人已经解释过的那样)。
如果你真的想这样做,你应该在方法定义中添加新关键字以使警告消失,并作为文档。因此,查看代码的其他开发人员知道您是故意这样做的。