new
和virtual
/ 之间有区别override
。
您可以想象,一个类在实例化时只不过是一个指向其方法的实际实现的指针表。下图可以很好地形象化此图像:

现在有不同的方法,可以定义一个方法。与继承一起使用时,它们的行为各不相同。标准方式始终如上图所示工作。如果要更改此行为,可以在方法中附加不同的关键字。
1.抽象类
第一个是abstract
。abstract
方法只是指向无处:

如果您的类包含抽象成员,则还需要将其标记为abstract
,否则编译器将不会编译您的应用程序。您不能创建abstract
类的实例,但可以从它们继承并创建继承的类的实例,并使用基类定义对其进行访问。在您的示例中,它看起来像:
public abstract class Person
{
public abstract void ShowInfo();
}
public class Teacher : Person
{
public override void ShowInfo()
{
Console.WriteLine("I am a teacher!");
}
}
public class Student : Person
{
public override void ShowInfo()
{
Console.WriteLine("I am a student!");
}
}
如果被调用,则行为会ShowInfo
根据实现而有所不同:
Person person = new Teacher();
person.ShowInfo(); // Shows 'I am a teacher!'
person = new Student();
person.ShowInfo(); // Shows 'I am a student!'
这两个,Student
S和Teacher
s为Person
S,但他们的行为不同,当他们被要求对自己的提示信息。但是,要求他们提示信息的方法是相同的:使用Person
类接口。
那么,当您继承时,幕后会发生什么Person
?在实现时ShowInfo
,指针不再指向无处,它现在指向实际的实现!创建Student
实例时,它指向Student
s ShowInfo
:

2.虚方法
第二种方法是使用virtual
方法。除了在基类中提供可选的默认实现外,其行为是相同的。virtual
可以实例化具有成员的类,但是继承的类可以提供不同的实现。这是您的代码实际上应该看起来像的样子:
public class Person
{
public virtual void ShowInfo()
{
Console.WriteLine("I am a person!");
}
}
public class Teacher : Person
{
public override void ShowInfo()
{
Console.WriteLine("I am a teacher!");
}
}
关键区别在于,基础成员Person.ShowInfo
不再指向无处。这也是为什么可以创建的实例的原因Person
(因此不再需要将其标记为abstract
):

您应该注意到,这看起来与第一张图片没有什么不同。这是因为该virtual
方法指向“ 标准方式 ”的实现。使用virtual
,你可以告诉Persons
,他们可以(不是必须),提供不同的实现ShowInfo
。如果您提供其他实现(使用override
),就像我在Teacher
上面所做的那样,则该图像将与相同abstract
。想象一下,我们没有为Student
s 提供自定义实现:
public class Student : Person
{
}
该代码将被这样调用:
Person person = new Teacher();
person.ShowInfo(); // Shows 'I am a teacher!'
person = new Student();
person.ShowInfo(); // Shows 'I am a person!'
的图像Student
如下所示:

3.神奇的“ new”关键字又称“ Shadowing”
new
更像是一个黑客。您可以在通用类中提供与基类/接口中的方法同名的方法。两者都指向自己的自定义实现:

实现看起来像您提供的那样。行为因您访问方法的方式而异:
Teacher teacher = new Teacher();
Person person = (Person)teacher;
teacher.ShowInfo(); // Prints 'I am a teacher!'
person.ShowInfo(); // Prints 'I am a person!'
可能需要这种行为,但在您的情况下却具有误导性。
我希望这可以使您更清楚地理解!