我对面向对象编程(OOP)的几个概念感到困惑,包括"virtual", "override", "new"和"sealed override"。有人可以解释一下它们之间的区别吗?
我很清楚,如果要使用派生类方法,可以使用"override"关键字覆盖基类方法。但是我不确定"new"和"sealed override"的作用。
我很清楚,如果要使用派生类方法,可以使用"override"关键字覆盖基类方法。但是我不确定"new"和"sealed override"的作用。
public class Base {
public virtual void SomeMethod() {
}
}
public class Derived : Base {
public override void SomeMethod() {
}
}
...
Base d = new Derived();
d.SomeMethod();
如果Derived类重写了Base类的SomeMethod方法,那么最终会调用Derived类的SomeMethod方法。
现在,如果你使用new关键字而不是override,那么派生类中的方法并不会重写基类中的方法,而只是隐藏它。在这种情况下,代码可能会像这样:
public class Base {
public virtual void SomeOtherMethod() {
}
}
public class Derived : Base {
public new void SomeOtherMethod() {
}
}
...
Base b = new Derived();
Derived d = new Derived();
b.SomeOtherMethod();
d.SomeOtherMethod();
virtual
关键字)或者不被覆盖。决定权在定义方法的人手中。class Person
{
// this one is not overridable (not virtual)
public String GetPersonType()
{
return "person";
}
// this one is overridable (virtual)
public virtual String GetName()
{
return "generic name";
}
}
class Friend : Person
{
public Friend() : this("generic name") { }
public Friend(String name)
{
this._name = name;
}
// override Person.GetName:
public override String GetName()
{
return _name;
}
}
GetPersonType
方法,因为它不是虚方法。Person person = new Person();
Friend friend = new Friend("Onotole");
GetPersonType
被Friend
实例调用时,实际上调用的是Person.GetPersonType
。Console.WriteLine(friend.GetPersonType()); // "person"
Friend
实例调用虚方法GetName
时,实际调用的是Friend.GetName
。Console.WriteLine(friend.GetName()); // "Onotole"
Person
实例调用虚拟方法GetName
时,调用的是Person.GetName
。Console.WriteLine(person.GetName()); // "generic name"
friend.GetName
,它从Friend
类开始查找,并立即找到;对于person.GetName
,它从Person
类开始查找,并在那里找到。sealed override
来实现这一点(表示你是最后一个重写该方法的人):class Mike : Friend
{
public sealed override String GetName()
{
return "Mike";
}
}
class Alice : Mike
{
public new String GetName()
{
return "Alice";
}
}
Alice alice = new Alice();
Console.WriteLine(alice.GetName()); // the new method is called, printing "Alice"
Console.WriteLine(((Mike)alice).GetName()); // the method hidden by new is called, printing "Mike"
virtual
或abstract
,否则方法无法在派生类中被重写。 virtual
表示“调用前检查新的实现”,而abstract
表示“相同”,但保证在所有派生类中被重写。此外,在基类中不需要实现它,因为它将在其他地方重新定义。new
修饰符。未声明为virtual
或abstract
的方法可以在派生类中使用new
修饰符重新定义。当在基类中调用该方法时,执行基本方法,而在派生类中调用时,执行新的方法。 new
关键字允许您在类层次结构中拥有两个名称相同的方法。sealed
修饰符打破了virtual
方法的链,使它们不能再次被覆盖。这不经常使用,但选项存在。它在三个类的链中派生自上一个类时更有意义。A -> B -> C
如果在类 A
中含有一个被类 B
重写的 virtual
或者 abstract
方法,那么可以通过在类 B
中将其声明为 sealed
来防止其他类如 C
再次改变它。
sealed
关键字同样用于 class
类中,这是你最常见到这个关键字的地方。
希望能对你有所帮助。
public class Base
{
public virtual void SomeMethod()
{
Console.WriteLine("B");
}
}
public class Derived : Base
{
//Same method is written 3 times with different keywords to explain different behaviors.
//This one is Simple method
public void SomeMethod()
{
Console.WriteLine("D");
}
//This method has 'new' keyword
public new void SomeMethod()
{
Console.WriteLine("D");
}
//This method has 'override' keyword
public override void SomeMethod()
{
Console.WriteLine("D");
}
}
开始
。 Base b=new Base();
Derived d=new Derived();
b.SomeMethod(); //will always write B
d.SomeMethod(); //will always write D
现在,关键词都与多态性有关。
Base b = new Derived();
virtual
,并在Derived
中使用override
可以实现D(多态)。Base
中使用override
而没有virtual
会导致错误。virtual
的方法(不覆盖)将带来警告'B'(因为未进行任何多态操作)。Derived
中的简单方法之前添加new
。new
关键字是另一种故事,它只是隐藏了警告,告诉我们在基类中存在相同名称的属性。virtual
或new
除了new修饰符之外是相同的
new
和override
不能在同一方法或属性前使用。
sealed
在任何类或方法之前锁定它以在派生类中使用,并且会产生编译时错误。
Derived
对象的实例,并将引用存储在Base
变量中。这是有效的,因为Derived
对象也是Base
对象。就像说我们需要一个“人”,所以我们得到了恰好是一个人的“Johnny”。这里也是同样的道理。 - Jeff MercadoBase b = new Derived()
表示一个Base
类可以通过Derived
类的引用进行访问,因为Derived
类是其基类的特化。Derived
类可以执行所有操作(例如调用基类方法等),而Base
类可以执行的操作则不能由其Derived
类执行。因此,Derived d = new Base()
是不正确的,但Base b = new Derived()
是正确的。 - mmushtaqnew
修饰符来隐藏基类方法的目的吗?在第二个例子中,调用b.SomeOtherMethod()
会调用基类实现(可以说它已经“隐藏”了派生类的方法)。如果这是一个典型的用法示例,那么当调用者打算使用编译时类型的变量来使用其方法而不是任何可能分配给它的运行时类型的方法时,似乎会使用new
。 - Minh Tran