为什么在基类引用中存储派生类型是合法的?

odi*_*seh 3 .net c# polymorphism inheritance

假设我们已经声明了这两个类:

public class Animal
{
    //.....
}

public class Dog : Animal
{
    //.....
}
Run Code Online (Sandbox Code Playgroud)

好吧,我的问题是:为什么下面的代码行有效?

Animal animal = new Dog();

编辑:

在电子书"专业C#2008"中,有一段说:

在基类引用中存储派生类型总是安全的.

Mar*_*ers 9

它起作用的原因是狗是动物(因为狗继承自动物)所以将狗对象分配给Animal类型的变量是合法的.

在另一个方向分配是不合法的.以下行将给出错误,因为Animal不从dog继承:

// Error: Cannot implicitly convert type 'Animal' to 'Dog'.
// An explicit conversion exists (are you missing a cast?)
Dog dog = new Animal();
Run Code Online (Sandbox Code Playgroud)

在某些情况下,你可能有一个类型为Animal的变量,但你知道它实际上必须是一个Dog.在这种情况下,您可以使用强制转换进行赋值,但如果对象实际上不是Dog,则此强制转换可能会在运行时失败.

Animal animal = new Cat();

// Unable to cast object of type 'Cat' to type 'Dog'.
Dog dog = (Dog)animal;
Run Code Online (Sandbox Code Playgroud)


slu*_*ter 5

你正在创建一个新的Dog,但是你正在处理(使用)它作为一个Animal.

当你想拥有一些由它拥有或暴露的行为时,这尤其有用Animal,但是Dog可能会用不同的东西覆盖它.在Dog可以用作或者是Dog或作为Animal,因为它是两个.

编辑:这是一个简单的例子,我将使用一个抽象基类,这样你就可以看到这种安排的真正价值:

public abstract class Animal
{
    public abstract void Move();

    public virtual void MakeSignatureSound() 
    {
        Console.WriteLine("Ugggg");
    }
}

public class Dog : Animal 
{
    public override void Move() 
    {
        RunLikeAPuppy();
    }

    public override void MakeSignatureSound()
    {
        Console.WriteLine("Woof");
    }
}

public class CaveMan : Animal
{
    public override void Move() 
    {
        RunLikeANeanderthal();
    }
}

public class Cat : Animal
{
    public override void Move() 
    {
        RunLikeAKitteh();
    }

    public override void MakeSignatureSound()
    {
        Console.WriteLine("Meioww");
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意两件事:

  • Animal该类中的所有三个衍生物都必须覆盖该Move()函数,因为在我的基类中我决定所有动物都应该有一个Move(),但我没有说明它们应该如何移动 - 这取决于个体动物指定
  • 在CaveMan类没有覆盖MakeSignatureSound()的功能,因为它已经在基类中定义,则他足够

现在,如果我这样做:

Animal caveman = new CaveMan();
Animal dog = new Dog();
caveman.MakeSignatureSound();
dog.MakeSignatureSound();
Run Code Online (Sandbox Code Playgroud)

我将在控制台上得到这个:

Ugggg
Woof
Run Code Online (Sandbox Code Playgroud)

但因为我使用了抽象基类,我不能直接实例化它的实例,我不能这样做:

Animal animal = new Animal();
Run Code Online (Sandbox Code Playgroud)

作为开发人员,我想确保当其他人(或我自己)创建新的时Animal,它必须是特定类型,而不仅仅是Animal没有行为或特征的纯粹类型.