我很迷惑OOP的一些概念:virtual
,override
,new
和sealed override
。任何人都可以解释不同之处虚拟,覆盖,新和密封覆盖之间的区别
我很清楚,如果要使用派生类方法,可以使用override
关键字,以便基类方法将被派生类重写。但我不确定new
和sealed override
。
我很迷惑OOP的一些概念:virtual
,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.SomeMethod(如果覆盖Base.SomeMethod)。现在
,如果使用新的关键字,而不是覆盖的,在派生类中的方法不重写基类中的方法,它只是隐藏它。在这种情况下,代码如下:
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();
首先调用Base.SomeOtherMethod,然后是Derived.SomeOtherMethod。它们实际上是两个完全分开的方法,它们碰巧具有相同的名称,而不是派生方法重写基本方法。
如果您没有指定新的或覆盖,则结果输出与您指定新的相同,但您也会收到编译器警告(因为您可能不知道隐藏了某个方法在基类方法中,或者实际上你可能想要覆盖它,并且只是忘记了包含关键字)。
重写属性声明可能包括密封修饰符。使用此修饰符可防止派生类进一步覆盖该属性。密封属性的访问者也被密封。
默认情况下,方法不能在派生类中重写,除非声明为virtual
或abstract
。 virtual
意思是在调用和abstract
意味着相同之前检查更新的实现,但它保证在所有派生类中被覆盖。而且,基类中不需要实现,因为它将在别处被重新定义。
上述例外是new
修饰符。未声明的方法virtual
或abstract
可以用派生类中的new
修饰符重新定义。当在基类中调用方法时执行基方法,并且在派生类中调用该方法时,将执行新方法。所有new
关键字允许您执行的操作是在类层次结构中使用和。
最后一个sealed
修饰符打破了virtual
方法的链并使它们不能再次覆盖。这不是经常使用,但选项在那里。更有意义与3类的链与前一个
A -> B -> C
如果A
具有virtual
或abstract
方法中的每个导出,也就是在B
overridden
,那么它也能防止C
更改它再次通过声明它sealed
在B
。
sealed
也用于classes
,那就是你会经常遇到这个关键字的地方。
我希望这会有所帮助。
任何方法都可以被覆盖(= 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
由Fiend
实例调用它实际上Person.GetPersonType
被称为:
Console.WriteLine(friend.GetPersonType()); // "person"
当虚方法GetName
被称为通过Friend
实例它是Friend.GetName
被称为:
Console.WriteLine(friend.GetName()); // "Onotole"
当虚拟方法GetName
由Person
例如它的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"
当您从Alice
调用它的角度来看,你叫Alice.GetName
,当从Mike
的 - 你叫Mike.GetName
。这里没有运行时查找 - 因为这两种方法都是非虚拟的。
您始终可以创建new
方法 - 您隐藏的方法是否为虚拟方法。
这也适用于属性和事件 - 它们被表示为下面的方法。
没有比我在任何地方发现的简单而完整的答案。谢谢Loki – Reevs 2018-02-27 19:22:49
public class Base
{
public virtual void SomeMethod()
{
Console.WriteLine("B");
}
}
//This one is Simple method
public class Derived : Base
{
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
覆盖会给d(多态性)。override
没有virtual
在Base
会给出错误。virtual
类似地写一个方法(没有覆盖)将写入'B'警告(因为没有多态性完成)。new
之前,在那个简单的方法Derived
。new
关键字是另一个故事,它只是隐藏警告,告诉同名的属性存在于基类中。virtual
或new
两者都是相同的,除了 new modifier
new
和override
之前相同的方法或特性可以不被使用。
sealed
之前任何类或方法锁定它将被用于派生类,它会给编译时错误。对不起,但-1因为多个编译错误:使用相同参数多次声明方法,字符串B&D周围没有引号... – DeveloperDan 2016-02-08 14:46:51
感谢您的意见..但有一件事并没有进入我的脑海中,是什么使用Base b = new Derived()?这是创建基类或派生类的对象? – 2011-05-28 15:49:05
派生类。我认为你必须更多地关注多态。这是您阅读的好帮手。 http://msdn.microsoft。com/en-us/library/ms173152(v = vs.80).aspx – CharithJ 2011-05-28 15:54:51
@Xor:在这种情况下,您正在创建一个Derived对象的实例并将该引用存储在Base变量中。这是有效的,因为Derived对象也是一个Base对象。这就像说我们需要一个“人”,所以我们得到了“约翰尼”,他恰好是一个人。这里同样如此。 – 2011-05-28 15:58:28