由于还没有回答,我会尽量给出一个好的答案。
看看下面的程序:
class Program
{
static void Main(string[] args)
{
Animal a = new Animal();
Cat c = new Cat();
Animal ac = new Cat();
a.Noise(a);
a.Noise(c);
a.Noise(ac);
c.Noise(a);
c.Noise(c);
c.Noise(ac);
a.Poop();
c.Poop();
ac.Poop();
Console.Read();
}
}
public class Animal
{
public void Noise(Animal a)
{
Console.WriteLine("Animal making noise!");
}
public void Poop()
{
Console.WriteLine("Animal pooping!");
}
}
public class Cat : Animal
{
public void Noise(Cat c)
{
Console.WriteLine("Cat making noise!");
}
public void Noise(Animal c)
{
Console.WriteLine("Animal making noise!");
}
public void Poop()
{
Console.WriteLine("Cat pooping in your shoe!");
}
}
输出:
Animal making noise!
Animal making noise!
Animal making noise!
Animal making noise!
Cat making noise!
Animal making noise!
Animal pooping!
Cat pooping in your shoe!
Animal pooping!
您可以看到我们创建了一个Animal 类型的变量a。它指向Animal 类型的对象。它有静态和运行时类型Animal。
接下来我们创建指向Cat 对象的Cat 变量。第三个对象是棘手的部分。我们创建了一个Animal 变量,它的运行时类型为Cat,但静态类型为Animal。为什么这很重要?因为在编译时您的编译器知道变量ac 实际上是Animal 类型。毫无疑问。所以它将能够完成Animal 对象可以做的所有事情。
但是,在运行时,变量内的对象已知为Cat。
为了演示我创建了 9 个函数调用。
首先,我们将对象传递给Animal 的实例。这个对象有一个接受Animal 对象的方法。
这意味着在Noise() 内部,我们可以使用Animal 类拥有的所有方法和字段。没有其他的。所以如果Cat 有一个方法Miauw(),我们就不能在不给我们的动物一个Cat 的情况下调用它。 (类型转换很脏,尽量避免它)。因此,当我们执行这 3 个函数调用时,我们将打印 3 次 Animal making noise!。清楚地。那么我的静态类型有什么关系呢?
好吧,我们马上就到那里。
接下来的三个函数调用是Cat 对象内的方法。 Cat 对象有两个方法Noise()。一个接受Animal,另一个接受Cat。
所以首先我们传递一个普通的Animal。运行时将查看所有方法并看到它有一个方法Noise,它采用Animal。正是我们需要的!所以我们执行那个并打印Animal 制造噪音。
下一个调用传递一个包含Cat 对象的Cat 变量。再一次,运行时会看看。我们是否有一个采用Cat 的方法,因为那是我的变量的类型。是的,是的,我们这样做。所以我们执行方法并打印"Cat making noise".
第三次调用,我们有我们的变量ac,它的类型是Animal,但指向一个Cat类型的对象。我们将看看是否能找到适合我们需求的方法。我们看一下静态类型(即变量的类型),我们看到它的类型是Animal,所以我们调用以Animal为参数的方法。
这是两者之间的细微差别。
接下来是大便。
所有动物都会拉屎。然而,一个Cat 会在你的鞋子里拉屎。所以我们重写基类的方法并实现它,这样Cat就在你的鞋里。
您会注意到,当我们在 Animal 上调用 Poop() 时,我们得到了预期的结果。 Cat c 也是如此。然而,当我们在ac 上调用Poop 方法时,我们看到这是一个Animal 便便并且你的鞋子是干净的。这是因为编译器又说我们的变量ac 的类型是Animal,你是这么说的。因此,它会调用Animal类型的方法。
我希望这对你来说已经足够清楚了。
编辑:
我这样想就记住了这一点:Cat x; 是一个类型为Cat 的盒子。盒子里没有猫,但是它的类型是Cat。这意味着盒子有一个类型,不管它的内容是什么。现在,当我在其中存储一只猫时:x = new Cat();,我在其中放入了一个类型为 Cat 的对象。所以我把一只猫放在猫盒里。但是,当我创建一个盒子Animal x; 时,我可以在这个盒子里存放动物。所以当我在这个盒子里放一个Cat 时,没关系,因为它是一种动物。所以x = new Cat() 把一只猫放在一个动物盒子里,这没关系。